/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       adventure_frame.cpp

	$Header: /game/adventure_frame.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )


#include "adventure_frame.h"

#include <fstream>
#include <strstream>
#include <stdio.h>
#include <utility>

#include "abbreviate_number.h"
#include "actor.h"
#include "adaptor_handler.h"
#include "adv_actor_model.h"
#include "adventure_ai.h"
#include "adventure_events_playback.h"
#include "adventure_map.h"
#include "adventure_map_window.h"
#include "adventure_path_finder.h"
#include "adventure_sounds.h"
#include "animated_window.h"
#include "animation_cache.h"
#include "army_dialog.h"
#include "army_list.h"
#include "army_list_window.h"
#include "army_mover.h"
#include "artifact_type.h"
#include "bitmap_group.h"
#include "bitmap_group_cache.h"
#include "bitmap_layer_window.h"
#include "bound_handler.h"
#include "button.h"
#include "button_bitmaps.h"
#include "button_cache.h"
#include "cached_grail_data_source.h"
#include "campaign_file_header.h"
#include "caravan.h"
#include "cheats.h"
#include "combat_context.h"
#include "combat_window.h"
#include "compressed_filter.h"
#include "creature_array_window.h"
#include "creature_traits.h"
#include "creature_type.h"
#include "debug_message.h"
#include "default_artifacts.h"
#include "dialog_campaign_score.h"
#include "dialog_caravan_view.h"
#include "dialog_kingdom_trade.h"
#include "dialog_marketplace.h"
#include "dialog_save_game.h"
#include "dialog_score.h"
#include "dialog_view_world.h"
#include "dump_entire_map_image.h"
#include "elements_of.h"
#include "enum_operations.h"
#include "external_string.h"
#include "function_handler.h"
#include "game_application.h"
#include "game_time.h"
#include "hero.h"
#include "interface_help.h"
#include "keyword_replacer.h"
#include "kingdom_overview_window.h"
#include "main_menu.h"
#include "map_header.h"
#include "material_icons.h"
#include "material_names.h"
#include "memory_window.h"
#include "mini_map_window.h"
#include "mouse_event.h"
#include "music.h"
#include "new_map_dialog.h"
#include "obelisk_reward.h"
#include "obelisk_reward_list.h"
#include "options.h"
#include "options_dialog.h"
#include "ownable_garrisonable_adv_object.h"
#include "owned_creature_array.h"
#include "pixel_24.h"
#include "platform.h"
#include "player.h"
#include "progress_bar_dialog.h"
#include "progress_handler.h"
#include "puzzle_window.h"
#include "quest_log_window.h"
#include "random.h"
#include "replace_keywords.h"
#include "resource.h"
#include "run_combat.h"
#include "saved_combat.h"
#include "scenario_info_window.h"
#include "scroll_menu.h"
#include "scrollbar.h"
#include "skill.h"
#include "skill_properties.h"
#include "simple_dialog.h"
#include "sound.h"
#include "sound_cache.h"
#include "spellbook_window.h"
#include "standard_fonts.h"
#include "text_window.h"
#include "thieves_guild_window.h"
#include "town_window.h"
#include "town_list.h"
#include "town_list_window.h"

#include "profile.h"

#ifdef VTUNE_API	// SCR 12/4/01
#include "..\vtune_api\VtuneAPI.h"
#endif


static int g_current_memory_checkpoint = 2;
static std::string	g_memory_output_file;

static t_bitmap_group_cache    g_adventure_interface_800(  "adventure.0800" );
static t_bitmap_group_cache    g_adventure_interface_1024( "adventure.1024" );
static t_bitmap_group_cache    g_adventure_interface_1280( "adventure.1280" );
static t_bitmap_group_cache    k_scroll_cursor( "cursor.scroll" );
static t_button_cache          g_system_menu_button( "button.system_menu" );
static t_button_cache          g_game_menu_button( "button.game_menu" );
static t_button_cache          k_move_army_button( "button.move_army" );
static t_button_cache          k_next_army_button( "button.next_army" );
static t_button_cache          k_overview_button( "button.overview" );
static t_button_cache          k_spell_button( "button.spell" );
t_button_cache                 g_surface_button( "button.surface" );
t_button_cache                 g_underground_button( "button.underground" );
static t_button_cache          g_end_turn_button( "button.end_turn" );
static t_button_cache const    k_army_mode_button( "button.army_list" );
static t_button_cache const    k_town_mode_button( "button.town_list" );
static t_button_cache const    k_dig_button( "button.dig" );
static t_button_cache const    k_find_army_button( "button.find_army" );
static t_button_cache const    k_quest_log_button( "button.quest_log" );
static t_button_cache const    k_view_puzzle_button( "button.view_puzzle" );
static t_button_cache const    k_caravan_button( "button.caravan" );
static t_button_cache const    k_marketplace_button( "button.marketplace" );
static t_button_cache const    k_next_town_button( "button.next_town" );
static t_button_cache const    k_replay_turn_button( "button.replay_turn" );
static t_button_cache const    k_kingdom_trade_button( "button.kingdom_trade" );
static t_button_cache const    k_view_world_button( "button.view_world" );
static t_button_cache const    k_thieves_guild_button( "button.thieves_guild" );

extern t_external_string const k_text_save_on_quit( "save.dialog" );
extern t_external_string const k_text_cancel_on_quit( "cancel" );
extern t_external_string const k_text_quit_on_quit( "quit" );

static t_external_string const k_text_game_menu( "game_menu" );
static t_external_string const k_text_system_menu( "system_menu" );
static t_external_string const k_move_army_help( "move_army.adventure_frame" );
static t_external_string const k_next_army_help( "next_army.adventure_frame" );
static t_external_string const k_overview_help( "overview.adventure_frame" );
static t_external_string const k_spell_help( "cast_spell.adventure_frame" );
static t_external_string const k_surface_help( "view_surface.adventure_frame" );	
static t_external_string const k_underground_help( "view_underground.adventure_frame" );
static t_external_string const k_text_players_turn( "player_turn.adventure_frame" );
static t_external_string const k_new_month_message( "new_month.message" );
static t_external_string const k_new_month_title( "new_month.title" );

extern t_animation_cache       g_sample_cursor;
static t_animation_cache       g_animated_cursor( "sample_animated_cursor" );
static t_animation_cache       g_end_turn_animation( "hourglass.flip" );
static t_bitmap_group_cache    g_day_scroll( "adventure.day_scroll" );
static t_external_string const k_month_text( "date.adventure_frame" );
static t_external_string const k_army_button_help( "army_list.adventure_frame" );
static t_external_string const k_town_button_help( "town_list.adventure_frame" );

static t_bitmap_group_cache    g_win_lose_window_1024( "dialog.win_lose.epilogue_1024" );
static t_bitmap_group_cache    g_win_lose_window_1280( "dialog.win_lose.epilogue_1280" );


static t_external_string const k_text_movement_left( "movement_left.misc" );
extern t_bitmap_group_cache g_small_town_list_bitmaps;
extern t_bitmap_group_cache g_army_rings;


// ---------------------------------------------------
// Unnamed namespace
// ---------------------------------------------------

namespace
{
	// hotkey resource strings
	t_external_string const k_hot_key_new_new_scenario( "new_scenario.hot_keys" );	// N + alt
	t_external_string const k_hot_key_new_campaign( "new_campaign.hot_keys" );		// C + alt
	t_external_string const k_hot_key_load_game( "load_game.hot_keys" );			// L + alt
	t_external_string const k_hot_key_save_game( "save_game.hot_keys" );			// S + alt
	t_external_string const k_hot_key_quit( "quit.hot_keys" );						// X + alt
	t_external_string const k_hot_key_options( "options.hot_keys" );				// O
	t_external_string const k_hot_key_marketplace( "marketplace.hot_keys" );		// M
	t_external_string const k_hot_key_thieves_guild( "thieves_guild.hot_keys" );	// G
	t_external_string const k_hot_key_kingdom_trade( "kingdom_trade.hot_keys" );	// R
	t_external_string const k_hot_key_dig( "dig.hot_keys" );						// D
	t_external_string const k_hot_key_view_world( "view_world.hot_keys" );			// V
	t_external_string const k_hot_key_replay_turn( "replay_turn.hot_keys" );		// L
	t_external_string const k_hot_key_restart_game( "restart_game.hot_keys" );		// R + alt
	t_external_string const k_hot_key_scenario_info( "scenario_info.hot_keys" );	// I
	t_external_string const k_hot_key_view_caravan( "view_caravan.hot_keys" );		// A
	t_external_string const k_hot_key_main_menu( "main_menu.hot_keys" );			// M + alt
	t_external_string const k_hot_key_overview( "overview.hot_keys" );				// K
	t_external_string const k_hot_key_under_over( "under_over.hot_keys" );			// U
	t_external_string const k_hot_key_end_turn( "end_turn.hot_keys" );				// E
	t_external_string const k_hot_key_cast_spell( "cast_spell.hot_keys" );			// C
	t_external_string const k_hot_key_wake_army( "wake_army.hot_keys" );			// W
	t_external_string const k_hot_key_sleep_army( "sleep_army.hot_keys" );			// Z
	t_external_string const k_hot_key_puzzle( "puzzle.hot_keys" );					// P
	t_external_string const k_hot_key_next_hero( "next_hero.hot_keys" );			// H 
	t_external_string const k_hot_key_next_town( "next_town.hot_keys" );			// T
	t_external_string const k_hot_key_quest_log( "quest_log.hot_keys" );			// Q

	t_external_string const k_text_army_wake( "army_wake.misc" );
	t_external_string const k_text_army_sleep( "army_sleep.misc" );

	t_counted_ptr<t_basic_dialog> g_quit_dialog; 

	bool g_enter_down_was_pressed = false;

	void set_visible_materials( t_material_display & materials, bool only_show_gold )
	{
		// In 800x600 mode only gold is visible
		if( only_show_gold )
		{
			materials.set_material_visible( k_gold, true );
			materials.set_material_visible( k_wood, false );
			materials.set_material_visible( k_ore, false );
			materials.set_material_visible( k_crystal, false );
			materials.set_material_visible( k_sulfur, false );
			materials.set_material_visible( k_mercury, false );
			materials.set_material_visible( k_gems, false );
		} else
		{
			materials.set_material_visible( k_gold, true );
			materials.set_material_visible( k_wood, true );
			materials.set_material_visible( k_ore, true );
			materials.set_material_visible( k_crystal, true );
			materials.set_material_visible( k_sulfur, true );
			materials.set_material_visible( k_mercury, true );
			materials.set_material_visible( k_gems, true );
		}
	}

	t_counted_ptr<t_dialog_cheat> g_cheats_window;	

	void set_day_text( t_text_window* window, int day )
	{
		int weekday = (day % k_days_per_week) + 1;
		int week    = ((day / k_days_per_week) % k_weeks_per_month) + 1;
		int month   = (day / k_days_per_month) + 1;

		std::string text = replace_keywords( k_month_text, 
							"%day", format_string( "%i", weekday),
							"%week", format_string( "%i", week),
							"%month", format_string( "%i", month) );

		window->set_text( text );
	}
} // namespace


// ----------------------------------------------------
// win/lose window to handle post game cinematics
// ----------------------------------------------------
t_win_lose_window::t_win_lose_window( t_window* parent, t_handler callback_handler )
				  : t_window( parent->get_client_rect(), k_completely_transparent, parent ),
					m_callback_handler( callback_handler ), m_end_handled( false )
{


	// override all the game's input
	// any mouse or key press will abort
	m_input_handler.reset( new t_override_input );

	t_handler cancel_handler = bound_handler( *this, &t_win_lose_window::cancel );
	m_input_handler->set_input_handler( cancel_handler );
}

// ------------------------------------------------------------------------
// win/lose window to handle post game cinematics
// ------------------------------------------------------------------------
void t_win_lose_window::cancel()
{
	// This bool is used, because multiple handlers can call this
	// and this window does not handle the closing of itself!
	if( !m_end_handled )
	{
		m_end_handled = true;
		m_input_handler.reset();
		m_callback_handler();
	}
}

// ------------------------------------------------------------------------
// win/lose window to handle post game cinematics
// ------------------------------------------------------------------------
void t_win_lose_window::end( t_window* )
{
	cancel();
}

/*
// ---------------------------------------------------
// speed test
// ---------------------------------------------------
t_bitmap_group_cache k_speed_test( "speed_test" );

void speed_test()
{
	t_bitmap_group_ptr bitmaps = k_speed_test.get();
	t_screen_rect      rect = bitmaps->get_rect();
	t_memory_bitmap16  dest( rect.width(), rect.height());
	int                i;
	t_bitmap_layer const* fast_layer = bitmaps->find( "fast" );
	t_bitmap_layer const* medium_layer = bitmaps->find( "medium" );
	t_bitmap_layer const* slow_1_layer = bitmaps->find( "slow_1" );
	t_bitmap_layer const* slow_2_layer = bitmaps->find( "slow_2" );
	t_bitmap_layer const* slow_3_layer = bitmaps->find( "slow_3" );

	{
		declare_timer( timer, "Fast drawing" );
		for (i = 0; i < 100; i++)
			fast_layer->draw_to( dest );
	}
	{
		declare_timer( timer, "medium drawing" );
		for (i = 0; i < 100; i++)
			medium_layer->draw_to( dest );
	}
	{
		declare_timer( timer, "slow 1 drawing" );
		for (i = 0; i < 100; i++)
			slow_1_layer->draw_to( dest );
	}
	{
		declare_timer( timer, "slow 2 drawing" );
		for (i = 0; i < 100; i++)
			slow_2_layer->draw_to( dest );
	}
	{
		declare_timer( timer, "slow 3 drawing" );
		for (i = 0; i < 100; i++)
			slow_3_layer->draw_to( dest );
	}
	dump_profile_markers();
}
*/

// ---------------------------------------------------
// class for animated day scroll
// ---------------------------------------------------
static int const k_frame_rate = 15;
static int const k_animation_time = 1000 / k_frame_rate;

t_day_scroll::t_day_scroll() : t_idle_processor( 1, k_animation_time )
{
	m_state = k_halted;
	m_bitmaps = g_day_scroll.get();
}

// ---------------------------------------------------
// class for animated day scroll
// ---------------------------------------------------
void t_day_scroll::init( t_screen_point point, int day, t_window* parent )
{
	t_window*				window;
	t_bitmap_layer const*	layer;
	t_screen_rect			rect;
	t_screen_point			origin;
	t_help_block const&		help = get_help_block( "adventure_map" );

	m_state = k_halted;
	// create background layer and clipper.
	layer = m_bitmaps->find( "background" );
	origin = layer->get_rect().top_left();
	rect = layer->get_rect() + point;
	m_maximum_width = rect.width();
	m_minimum_width = m_bitmaps->find( "left" )->get_rect().right - origin.x;
	m_window = new t_window( rect, t_window::k_completely_transparent, parent );
	window = new t_bitmap_layer_window( layer, t_screen_point(0,0), m_window, false );

	// create text
	rect = m_bitmaps->find( "text" )->get_rect() - origin;
	m_text = new t_text_window( get_font( rect.height() / 2 ), rect, m_window, "",
		                               t_pixel_24(0,0,0) );
	m_text->set_drop_shadow( true, t_pixel_24(200,200,200) );
	m_text->set_center_horizontal();

	// create right edge
	layer = m_bitmaps->find( "right" );
	m_edge = new t_bitmap_layer_window( layer, point, parent );

	m_day = day;
	set_day_text( m_text, day );

	// create the help
	set_help( m_text, help, "calendar" );
}

// ---------------------------------------------------
// class for animated day scroll
// ---------------------------------------------------
void t_day_scroll::new_day( int day )
{
	if (day == m_day)
		return;

	// start rolling left.
	m_state = k_rolling_left;
	m_day = day;
	if (!is_active())
		resume_idle_processing();
}

// ---------------------------------------------------
// class for animated day scroll
// ---------------------------------------------------
void t_day_scroll::on_idle()
{
	static int const k_frame_size = 20;

	// wait until it's time to animate
	if (m_state == k_halted)
	{
		suspend_idle_processing();
		return;
	}

	t_screen_rect rect;
	int           width;

	// update timer
	rect = m_window->get_screen_rect();
	if (m_state == k_rolling_left)
	{   // reduce width of scroll
		width = rect.width() - k_frame_size;
		if (width <= m_minimum_width)
		{   // if at limit, change text and switch to unrolling.
			width = m_minimum_width;
			m_state = k_rolling_right;
			set_day_text( m_text, m_day );
		}
	}
	else
	{   // increase width of scroll
		assert( m_state == k_rolling_right );
		width = rect.width() + k_frame_size;
		if (width >= m_maximum_width)
		{   // if at limit, halt.
			width = m_maximum_width;
			m_state = k_halted;
			suspend_idle_processing();
		}
	}

	// record the change in size.
	int delta = width - rect.width();

	rect.right = rect.left + width;
	m_window->move_screen_rect( rect );

	// move the right edge to match the new scroll size.
	rect = m_edge->get_screen_rect();
	rect.left += delta;
	rect.right += delta;
	m_edge->move_screen_rect( rect );
	redraw_windows();
}

t_turn_duration_timer::t_turn_duration_timer() : t_idle_processor( 0, 250 )
{
    m_frame = NULL;
}

void t_turn_duration_timer::init( t_adventure_frame* frame_ptr )
{
    m_frame = frame_ptr;
    m_map = frame_ptr->get_map();
    m_frame->reset_turn_time();
}

void t_turn_duration_timer::on_idle()
{
    if (!m_frame)
        return;
    
	int index = m_map->get_turn_duration_index();

    // Paused.
    if (m_frame->get_saved_elapsed_time())
        return;
    
    //if (m_frame->get_elapsed_turn_time() >= g_turn_lengths[index] )
    //{
    //    m_frame->force_end_turn();
	//    m_frame->reset_turn_time();
    //}
}


// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
int const k_scroll_delay = 50;

t_adventure_frame::t_adventure_frame( t_adventure_map* adventure_map, t_window* parent ) 
				 : t_window( k_no_transparency, parent ), t_idle_processor( 0, 50 )
{
	m_team_view = -1;
	m_adventure_map = adventure_map;
	m_adventure_normal_map = NULL;
	m_adventure_replay_map = NULL;
	m_allow_scrolling = true;
	m_selected_army = 0;
	m_selected_town = 0;
	m_scroll_distance = 25;
	m_scrolling = false;
	m_mouse_direction = k_direction_count;
	m_distance = 0;
	m_army_display = 0;
	m_in_replay_mode = false;
    m_turn_time = 0;
    m_turn_time_elapsed = 0;
	m_path_finder = NULL;
	m_end_turn_animation = g_end_turn_animation.get();

	m_turn_duration_timer.init( this );
	move_memory_window_to_front();

	set_resolution( parent->get_width() );

	init( parent->get_client_rect() );

	m_scroll_cursor.create( k_scroll_cursor.get() );
	m_normal_cursor = new t_mouse_window;

	t_window* animation = new t_animated_window( g_sample_cursor.get(), 
		                                         t_screen_point(0,0), 100, m_normal_cursor );
	set_cursor( m_normal_cursor );

	suspend_idle_processing();
}

// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
t_adventure_frame::~t_adventure_frame()
{
	if (m_adventure_map_window != 0)
		m_adventure_map_window->set_frame( 0 );
}

void t_adventure_frame::add_to_non_permanent_windows_list(t_window_ptr window)
{
	m_non_permanent_windows.push_back( window );
}

// ----------------------------------------------------
// frame window for adventure map
// open up the system menu 
// ----------------------------------------------------
static t_external_string const k_text_new_scenario( "new_scenario" );
static t_external_string const k_text_new_campaign( "new_campaign" );
static t_external_string const k_text_load_game( "load_game" );
static t_external_string const k_text_save_game( "save_game" );
static t_external_string const k_text_restart_game( "restart_game" );
static t_external_string const k_text_main_menu( "main_menu" );
static t_external_string const k_text_options( "options" );
extern t_external_string const k_text_quit( "quit" );

void t_adventure_frame::materials_cheat()
{
	m_adventure_map->add_free_materials();
	update_funds();
}



void t_adventure_frame::resize_view( t_screen_rect const& new_size_pos)
{
	if (m_mini_map != 0)
		m_mini_map->resize_view(new_size_pos);
}

void t_adventure_frame::set_team_view()
{
	assert( m_adventure_map_window != 0 );
	if ( get_enable_shroud() )
	{
		int player_number = m_adventure_map->get_player_number();
		if ( player_number >= 0 && player_number < m_adventure_map->get_player_count() )
		{
			set_team_view( m_adventure_map->get_player( player_number ).get_team() );
		}
	}
}

void t_adventure_frame::set_team_view( int new_team_view )
{
	if ( new_team_view == m_team_view || ( !get_enable_shroud() && new_team_view >= 0 ) )
		return;

	if (m_mini_map != 0)
		m_mini_map->set_team_view( new_team_view );
	if (m_adventure_map_window != 0)
		m_adventure_map_window->set_team_view( new_team_view );

	m_team_view = new_team_view;
}

int t_adventure_frame::get_team_view() const
{
	return m_team_view;
}


void t_adventure_frame::system_menu( t_button* button )
{
	if ( !m_adventure_map_window->halt_movement() )
		return;
	m_adventure_map_window->clear_spell_targeter();

	t_scroll_menu* menu = new t_scroll_menu( this );

	menu->add_item( k_text_new_scenario, bound_handler( *this, &t_adventure_frame::new_scenario) );
	menu->add_item( k_text_new_campaign, bound_handler( *this, &t_adventure_frame::new_campaign) );
	menu->add_item( k_text_load_game, bound_handler( *this, &t_adventure_frame::load_game ));
	menu->add_item( k_text_save_game, bound_handler( *this, &t_adventure_frame::save_handler ));
	menu->add_item( k_text_restart_game, bound_handler( *this, &t_adventure_frame::restart_game ));
	menu->add_item( k_text_options, bound_handler( *this, &t_adventure_frame::options ));
	menu->add_item( k_text_main_menu, bound_handler( *this, &t_adventure_frame::main_menu ));
	menu->add_item( k_text_quit, bound_handler( *this, &t_adventure_frame::quit ));
	if (show_cheat_menus())
	{
		menu->add_item( "Free Materials", 
						bound_handler( *this, &t_adventure_frame::materials_cheat ));
		menu->add_item( "Dump profile times", function_handler( dump_profile_markers ) );
		menu->add_item( "Verify external strings", function_handler( verify_external_strings ));
		if (m_selected_army != 0)
			menu->add_item( "Learn All Spells", bound_handler( *this, 
							&t_adventure_frame::learn_spells_cheat ));
	}
	menu->open( to_client( button->get_screen_rect() ).top_left() );
}

// ----------------------------------------------------
// frame window for adventure map
// reset path finder
// ----------------------------------------------------
void t_adventure_frame::reset_pathfinder()
{
	m_path_finder->clear();
	m_adventure_map->reset_danger();
}


// ----------------------------------------------------
// frame window for adventure map
// handle a new adventure map, through either loading map or 
// loading saved game
// ----------------------------------------------------
void t_adventure_frame::initialize()
{
	m_team_view = -1;
	m_selected_army = NULL;
	m_selected_town = NULL;
	t_player & player = m_adventure_map->get_player();
	m_material_display.set_player( &player );
	m_material_display_gold.set_player( &player );
	m_town_list->set_map( *m_adventure_map );
	m_town_list->set_town_list( player.get_towns(), player.get_team() );
	m_army_list->set_army_array( player.get_armies() );
	m_path_finder = new t_adventure_path_finder( *m_adventure_map );

	// (re)create our interface windows
	set_resolution( get_parent()->get_width() );

	// Prepare the players initial state	
	{
		if (m_adventure_map->is_hotseat())
		{
			t_player_info_hider hider( *this );
			ok_dialog( replace_keywords( k_text_players_turn, "%player_name", m_adventure_map->get_current_player().get_name() ), true );
		}

		select_first_item();
		update();
		refresh_path();
	}

	// Get ourselves displaying the appropriate level of the map
	set_view_level( m_adventure_map_window->get_view_level() ); 

	// Restart the turn timer
	reset_turn_time();
}


// ----------------------------------------------------
// frame window for adventure map
// new game clicked
// ----------------------------------------------------
void t_adventure_frame::start_new_game( t_adventure_map_ptr new_map )
{
	m_adventure_map = new_map;
	initialize();

	m_adventure_map->get_ai().start_game();
	m_adventure_map->process_timed_events( this );
	update();
}

// ----------------------------------------------------
// frame window for adventure map
// new scenario clicked
// ----------------------------------------------------
void t_adventure_frame::new_scenario()
{
	assert( m_adventure_map_window );

	if ( !m_adventure_map_window->halt_movement() )
		return;
	m_adventure_map_window->clear_spell_targeter();

	m_adventure_map_window->enable_animation( false );

	t_adventure_map_ptr new_map = read_new_game( this );
	if (new_map == 0)
	{
		m_adventure_map_window->enable_animation( show_adventure_animations() );
		return;
	}
	start_new_game( new_map );
}


// ----------------------------------------------------
// frame window for adventure map
// new campaign clicked
// ----------------------------------------------------
void t_adventure_frame::new_campaign()
{
	assert( m_adventure_map_window );

	if ( !m_adventure_map_window->halt_movement() )
		return;
	m_adventure_map_window->clear_spell_targeter();

	m_adventure_map_window->enable_animation( false );

	t_adventure_map_ptr new_map;
	if( start_new_campaign( new_map ) )
	{
		m_adventure_map_window->enable_animation( show_adventure_animations() );
		start_new_game( new_map );
	}
}


t_external_string const k_text_question_restart_game( "restart_game.misc" );
// ----------------------------------------------------
// frame window for adventure map
// Restart game.
// ----------------------------------------------------
void t_adventure_frame::restart_game()
{
	assert( m_adventure_map_window );

    if (!(yes_no_dialog( k_text_question_restart_game )))
        return;

	if ( !m_adventure_map_window->halt_movement() )
		return;
	m_adventure_map_window->clear_spell_targeter();

	m_adventure_map_window->enable_animation( false );

	t_adventure_map_ptr new_map = read_restarted_game( this, m_adventure_map );
	if (new_map == 0)
	{
		m_adventure_map_window->enable_animation( show_adventure_animations() );
		return;
	}

    // Set to new map.
	start_new_game( new_map );
}


// ----------------------------------------------------
// frame window for adventure map
// load game clicked
// ----------------------------------------------------
void t_adventure_frame::load_game()
{
	assert( m_adventure_map_window );

	if ( !m_adventure_map_window->halt_movement() )
		return;
	m_adventure_map_window->clear_spell_targeter();

	m_adventure_map_window->enable_animation( false );

	t_adventure_map_ptr new_map = read_saved_game( this );
	if (new_map == 0)
	{
		m_adventure_map_window->enable_animation( show_adventure_animations() );
		return;
	}

	t_adventure_map_ptr	old_map = m_adventure_map;

	m_adventure_map = new_map;
	start_saved_game();
}

// ----------------------------------------------------
// frame window for adventure map
// new game clicked
// ----------------------------------------------------
void t_adventure_frame::start_saved_game()
{
	initialize();
	set_day( m_adventure_map->get_day() );
	if (m_adventure_map->get_saved_combat() != 0)
	{
		m_adventure_map->get_saved_combat()->launch( m_adventure_map, this );
	}
	else
	{
		update();
	}
}

// ----------------------------------------------------
// frame window for adventure map
// create the adventure map window
// ----------------------------------------------------
void t_adventure_frame::create_adventure_map_window()
{
	t_bitmap_layer const*	element;
	t_screen_rect			rect;
	t_help_block const&		help = get_help_block( "adventure_map" );

	element = m_interface_background->find( "left" );
	rect.left = element->get_rect().right;
	element = m_interface_background->find( "top" );
	rect.top = element->get_rect().bottom;
	element = m_interface_background->find( "right" );
	rect.right = element->get_rect().left;
	element = m_interface_background->find( "bottom" );
	rect.bottom = element->get_rect().top;

	m_adventure_map_window = new t_adventure_map_window( rect, this );
	m_adventure_map->attach( m_adventure_map_window );
	m_adventure_map_window->set_team_view( m_team_view );
	m_adventure_map_window->set_help_balloon_text( "Adventure map" );
	m_adventure_map_window->move_to_back();

	element = m_interface_background->find( "mini_map" );
	if (element != 0)
	{
		rect = element->get_rect();
		rect -= to_client( m_right_bar->get_screen_rect().top_left() );
		m_mini_map = new t_mini_map_window( *m_adventure_map, rect, m_adventure_map_window,
			                                m_right_bar, m_team_view );
		set_help( m_mini_map, help, "mini_map" );
	}
}

t_adventure_map* t_adventure_frame::get_map() const
{
	return m_adventure_map;
}

// ----------------------------------------------------
// handler for moving the currently selected army
// via the move army button
// ----------------------------------------------------
void t_adventure_frame::move_selected_army( t_button* )
{
	if( m_selected_army && !get_map_window()->get_object_mover() )
	{
		// start army moving.
		start_army_moving( m_selected_army );
	} 
	else 
	{
		// Stop the army in motion
		m_adventure_map_window->halt_movement();
	}
}

// ----------------------------------------------------
// frame window for adventure map
// create buttons
// ----------------------------------------------------
static t_external_string k_end_turn( "end_turn.adventure_frame" );

t_button* t_adventure_frame::create_button( char const*			  name, 
										    t_button_cache const& button_cache,
											t_screen_point        origin )
{
	t_button*			  button;
	t_screen_rect		  rect;
	t_bitmap_layer const* layer;
	std::string           layer_name = name;

	layer_name += "_button";
	layer = m_interface_background->find( layer_name );
	if (layer == 0)
		return 0;

	t_help_block const&		help = get_help_block( "adventure_map" );

	rect = layer->get_rect();
	button = new t_button( button_cache.get(), rect.top_left() - origin, m_right_bar );
	set_help( button, help, name );
	return button;
}

void t_adventure_frame::create_buttons()
{
	// create the menu buttons.
	t_screen_rect			rect;
	t_button*				button;
	t_screen_point			origin;
	t_help_block const&		help = get_help_block( "adventure_map" );
	t_bitmap_layer const*	layer;

	origin = to_client( m_right_bar->get_screen_rect().top_left() );
	rect = m_interface_background->find( "system_menu_button" )->get_rect();
	button = new t_button( g_system_menu_button.get(), rect.top_left() - origin, m_right_bar );
	set_help( button, help, "system_menu" );
	button->set_click_handler( bound_handler( *this, &t_adventure_frame::system_menu ) );
	
	// resources roll out
	if( layer = m_interface_background->find( "gold_background" ) )
	{
		rect = layer->get_rect();
		button = new t_button( g_game_menu_button.get(), rect.top_left() - origin, m_right_bar );
		set_help( button, help, "game_menu" );
		button->set_click_handler( bound_handler( *this, &t_adventure_frame::game_menu ));
	}

	// game menu button
	if( layer = m_interface_background->find( "game_menu_button" ) )
	{
		rect = layer->get_rect();
		button = new t_button( g_game_menu_button.get(), rect.top_left() - origin, m_right_bar );
		set_help( button, help, "game_menu" );
		button->set_click_handler( bound_handler( *this, &t_adventure_frame::game_menu ));
	}

	// move army button
	if( layer = m_interface_background->find( "move_army_button" ) )
	{
		rect = layer->get_rect();
		m_move_army_button = new t_button( k_move_army_button.get(), rect.top_left() - origin, m_right_bar );
		set_help( m_move_army_button, help, "move_army" );
		m_move_army_button->set_click_handler( bound_handler( *this, &t_adventure_frame::move_selected_army ) );
	}

	// overview button
	if( layer = m_interface_background->find( "overview_button" ) )
	{
		rect = layer->get_rect();
		m_overview_button = new t_button( k_overview_button.get(), rect.top_left() - origin, m_right_bar );
		set_help( m_overview_button, help, "kingdom_overview" );
		m_overview_button->set_click_handler( bound_handler( *this, &t_adventure_frame::kingdom_overview_click ) );
	}

	// spell button
	t_button_handler handler;

	if( layer = m_interface_background->find( "spell_button" ) )
	{
		rect = layer->get_rect();
		m_spell_button = new t_button( k_spell_button.get(), rect.top_left() - origin, m_right_bar );
		handler = bound_handler( *this, &t_adventure_frame::spellbook_click );
		m_spell_button->set_click_handler( handler );
		set_help( m_spell_button, help, "cast_spell" );
	}

	// Marketplace
	if( m_interface_background->find( "marketplace_button" ) )
	{
		m_marketplace_button = create_button( "marketplace", k_marketplace_button, origin );
		if ( m_marketplace_button )
		{
			m_marketplace_button->set_click_handler( discard_argument< t_button * >( bound_handler( *this, &t_adventure_frame::marketplace ) ) );
		}
	}

	// surface button
	if( layer = m_interface_background->find( "surface_button" ) )
	{
		rect = layer->get_rect();
		m_surface_button = new t_button( g_surface_button.get(), rect.top_left() - origin, m_right_bar );
		set_help( m_surface_button, help, "surface" );
		m_surface_button->set_click_handler( bound_handler( *this, &t_adventure_frame::layer_view_click ));
		m_surface_button->set_visible( false );
	}

	// underground button
	if( layer = m_interface_background->find( "underground_button" ) )
	{
		rect = layer->get_rect();
		m_underground_button = new t_button( g_underground_button.get(), rect.top_left() - origin, m_right_bar );
		set_help( m_underground_button, help, "underground" );
		m_underground_button->set_click_handler( bound_handler( *this, &t_adventure_frame::layer_view_click ));
		if(	m_adventure_map->get_num_levels() <= 1 )
			m_underground_button->enable( false );
	}

	// end turn button
	if( layer = m_interface_background->find( "end_turn" ) )
	{
		rect = layer->get_rect();
		m_end_turn_button = new t_button( g_end_turn_button.get(), rect.top_left() - origin, m_right_bar );
		set_help( m_end_turn_button, help, "end_turn" );
		m_end_turn_button->set_click_handler( bound_handler( *this, &t_adventure_frame::end_turn_click ));
	}

	// end turn animation
	t_screen_rect  first_frame_rect = m_end_turn_animation->front()->get_rect();
	t_screen_point offset = rect.top_left() - first_frame_rect.top_left() - origin;

	m_end_turn_animation_window = new t_animated_window( m_end_turn_animation, offset, 100, 
														 m_right_bar );
	m_end_turn_animation_window->set_visible( false );
	m_end_turn_animation_window->enable_animation( false );
	m_end_turn_animation_window->set_range( 0, m_end_turn_animation->size(), false );
	m_end_turn_animation_window->set_end_handler( bound_handler( *this, 
												  &t_adventure_frame::end_turn_animation_finished ));
}

static int const k_number_of_holes = 2;
static char const* k_hole_list[ k_number_of_holes ] =
{
	"cracks-holes.hole01",
	"cracks-holes.hole02"
};

static t_external_string const k_text_dig_denied( "dig_denied.dialog" );
static t_external_string const k_text_dig_success( "dig_success.dialog" );
static t_external_string const k_text_dig_failed( "dig_failed.dialog" );
static t_external_string const k_text_dig_on_bridge( "dig_on_bridge.dialog" );

void t_adventure_frame::dig()
{
    int                     i;
    t_army *                army_ptr = get_selected_army();

	// Make sure we have an army to do the digging
	if (!army_ptr) {
		assert( false );
		return;
	}

	t_adv_map_point    army_point = army_ptr->get_position();

	if ( army_point.on_bridge )
	{
		ok_dialog( k_text_dig_on_bridge );
		return;
	}


    // Army needs full movement to dig.
    if ( army_ptr->get_movement() < army_ptr->get_max_movement() )
    {
        t_counted_ptr<t_basic_dialog> denied_dialog_ptr;

        denied_dialog_ptr = new t_basic_dialog;
        denied_dialog_ptr->set_text( k_text_dig_denied );

        denied_dialog_ptr->add_ok_button();
        denied_dialog_ptr->open();
        denied_dialog_ptr->run_modal();

        return;
    }

    // Expend movement.
    army_ptr->expend_all_movement();
	refresh_path();

    // Add hole - check if hole already exists?
    int                         hole_index = random( k_number_of_holes );
    t_stationary_adventure_object*   hole_ptr = new t_stationary_adventure_object ( k_hole_list[hole_index] );
    bool                        found_obelisk = false;

    hole_ptr->place( *m_adventure_map, army_point );

    // Check if obelisk treasure are here.  If so, give hero benefit.
    for (t_obelisk_color color = k_obelisk_gold; color < k_obelisk_color_count; enum_incr( color ))
    {
	    t_level_map_point_2d artifact_point = m_adventure_map->get_obelisk_artifact_position( color );

        // Is the artifact at this point?
        if (artifact_point == army_point)
        {
            // Get reward(s) for this obelisk.
	        t_obelisk_reward_list reward_list = m_adventure_map->get_obelisk_reward_list( color );

            t_counted_ptr<t_basic_dialog> result_dialog_ptr;
            result_dialog_ptr = new t_basic_dialog;
            result_dialog_ptr->set_text( k_text_dig_success );

            // Give player rewards...
            for (i=0; i<reward_list.size(); i++)
            {
                reward_list[i]->give_reward( army_ptr );
                // Show what was gotten.
                reward_list[i]->add_to_basic_dialog( *result_dialog_ptr );
            }

            // Nullify position, so it can't be used again.
            m_adventure_map->set_obelisk_artifact_position ( color, t_level_map_point_2d (-1, -1, 0) );
            m_adventure_map->set_obelisk_completed( color );
        
            result_dialog_ptr->add_ok_button();
            result_dialog_ptr->open();
            result_dialog_ptr->run_modal();

            found_obelisk = true;
        }
    }
	update_funds();

	// play the dig sound
	get_adventure_sound( k_adventure_sound_dig )->play( get_sound_volume() );

    if (found_obelisk == false)
    {
        t_counted_ptr<t_basic_dialog> failed_dialog_ptr;
        failed_dialog_ptr = new t_basic_dialog;
        failed_dialog_ptr->set_text( k_text_dig_failed );

        failed_dialog_ptr->add_ok_button();
        failed_dialog_ptr->open();
        failed_dialog_ptr->run_modal();
    }
}

// ----------------------------------------------------
// frame window for adventure map
// cast spell button
// ----------------------------------------------------
void t_adventure_frame::spellbook_click( t_button* )
{
	t_creature_array* creatures = get_selected_creatures();
	if ( creatures == 0 )
		return;

	int slot = get_selected_creature_slot();
	if ( slot < 0 )
		return;

	t_counted_ptr<t_spellbook_window> dialog;

	if ( !m_adventure_map_window->halt_movement() )
		return;
	m_adventure_map_window->clear_spell_targeter();

	t_cached_grail_data_source grail_data( creatures->get_grail_data() );

	dialog = new t_spellbook_window( &(*creatures)[slot], this, grail_data, t_spellbook_window::k_open_adventure );
	if (!dialog->run_modal())
		return;

	cast_adventure_spell( *creatures, slot,
		                  dialog->get_selected_spell() );
}
			 
// ----------------------------------------------------
// frame window for adventure map
// set up for a new resolution
// ----------------------------------------------------
void t_adventure_frame::set_resolution( int width )
{
	// close all previous interface windows
	t_window_list::iterator child_window;

	for (child_window = m_interface_windows.begin(); child_window != m_interface_windows.end();
	     child_window++)
		(*child_window)->close();
	m_interface_windows.clear();

	if (m_adventure_map_window != 0)
	{
		m_adventure_map_window->close();
		m_adventure_map_window = 0;
		if (m_adventure_map != 0)
			m_adventure_map->attach( 0 );
	}
	if (m_mini_map != 0)
	{
		m_mini_map->close();
		m_mini_map = 0;
	}

	switch (width)
	{
		case 800:
			m_interface_background = g_adventure_interface_800.get();
			break;

		case 1024:
			m_interface_background = g_adventure_interface_1024.get();
			break;

		case 1280:
			m_interface_background = g_adventure_interface_1280.get();
			break;
	}

	for (child_window = m_stats_icons.begin(); child_window != m_stats_icons.end();
	     child_window++)
		(*child_window)->close();

	t_window*                child;
	t_bitmap_layer const*    right_bar_bitmap;
	t_bitmap_layer const*    resource_bar_bitmap;
	t_bitmap_layer const*    gold_bar_bitmap;
	t_screen_point           origin(0,0);

	if( width == 800 )
	{
		m_resources_bar = new t_button( origin, this );
		m_resources_bar->set_click_handler( bound_handler( *this, &t_adventure_frame::resources_bar_clicked ));
		resource_bar_bitmap = m_interface_background->find( "resources_background" );
		child = new t_bitmap_layer_window( resource_bar_bitmap, origin, m_resources_bar );
		m_resources_bar->set_released_image( child );
		m_resources_bar->set_visible( false );
		m_interface_windows.push_back( m_resources_bar );

		m_gold_bar = new t_button( origin, this );
		m_gold_bar->set_click_handler( bound_handler( *this, &t_adventure_frame::gold_bar_clicked ));
		gold_bar_bitmap = m_interface_background->find( "gold_background" );
		child = new t_bitmap_layer_window( gold_bar_bitmap, origin, m_gold_bar );
		m_gold_bar->set_released_image( child );
		m_interface_windows.push_back( m_gold_bar );
	}

	child = new t_bitmap_layer_window( m_interface_background->find( "top" ), origin, this );
	m_interface_windows.push_back( child );
	child = new t_bitmap_layer_window( m_interface_background->find( "top_border" ), origin, this );
	m_interface_windows.push_back( child );
	child = new t_bitmap_layer_window( m_interface_background->find( "left" ), origin, this );
	m_interface_windows.push_back( child );
	child = new t_bitmap_layer_window( m_interface_background->find( "left_border" ), origin, this );
	m_interface_windows.push_back( child );
	right_bar_bitmap = m_interface_background->find( "right" );
	m_right_bar = new t_bitmap_layer_window( right_bar_bitmap, origin, this );
	m_interface_windows.push_back( m_right_bar );
	child = new t_bitmap_layer_window( m_interface_background->find( "right_border" ), origin, this );
	m_interface_windows.push_back( child );
	child = new t_bitmap_layer_window( m_interface_background->find( "bottom" ), origin, this );
	m_interface_windows.push_back( child );
	child = new t_bitmap_layer_window( m_interface_background->find( "bottom_border" ), origin, this );
	m_interface_windows.push_back( child );

	create_adventure_map_window();

	// create the menu buttons.
	origin = to_client( m_right_bar->get_screen_rect().top_left() );
	create_buttons();
	m_creature_detail.create( m_interface_background, m_right_bar, origin, m_right_bar, origin );

    // Stats icons.
	t_help_block const&     shared_help_block = get_help_block( "shared" );
	if( width == 1280 )
	{
	    child = new t_bitmap_layer_window( m_interface_background->find( "health_icon" ), t_screen_point(0,0), this );
   	    set_help( child, shared_help_block, "hit_points" );
	    m_stats_icons.push_back( child );
	    child = new t_bitmap_layer_window( m_interface_background->find( "damage_icon" ), t_screen_point(0,0), this );
   	    set_help( child, shared_help_block, "damage" );
	    m_stats_icons.push_back( child );
	    child = new t_bitmap_layer_window( m_interface_background->find( "move_icon" ), t_screen_point(0,0), this );
   	    set_help( child, shared_help_block, "movement" );
	    m_stats_icons.push_back( child );
	    child = new t_bitmap_layer_window( m_interface_background->find( "mana_icon" ), t_screen_point(0,0), this );
   	    set_help( child, shared_help_block, "spell_points" );
	    m_stats_icons.push_back( child );
    }

	// materials icons
	if( width == 800 )
	{
		set_visible_materials( m_material_display, false );
		m_material_display.init( m_interface_background, &m_adventure_map->get_player(),
								 resource_bar_bitmap->get_rect().top_left(), m_resources_bar );
		set_visible_materials( m_material_display_gold, true );
		m_material_display_gold.init( m_interface_background, &m_adventure_map->get_player(),
								 gold_bar_bitmap->get_rect().top_left(), m_gold_bar );
	} else
		m_material_display.init( m_interface_background, &m_adventure_map->get_player(),
								 right_bar_bitmap->get_rect().top_left(), m_right_bar );

	// create scrollbars
	t_screen_rect rect;
	t_screen_rect frame_rect;

	rect = m_interface_background->find( "town_scrollbar" )->get_rect();
	m_town_scrollbar = new t_scrollbar( rect.top_left() - origin, rect.height(), m_right_bar, 0, 0 );

	rect = m_interface_background->find( "army_scrollbar" )->get_rect();
	m_army_scrollbar = new t_scrollbar( rect.top_left() - origin, rect.height(), m_right_bar, 0, 0 );

	// create town list **note the town list window must be attached to a town list before it can be used. It is 
	//used indirectly through the select_army function.**
	t_player & player = m_adventure_map->get_player();

	rect = m_interface_background->find( "town_list" )->get_rect();
	frame_rect = g_small_town_list_bitmaps.get()->find( "frame" )->get_rect();
	rect.right = rect.left + frame_rect.width();
	m_town_list = new t_town_list_window( rect - origin, m_right_bar, true );
	m_town_list->set_select_handler( bound_handler( *this, &t_adventure_frame::select_town ) );
	m_town_list->set_double_click_handler( bound_handler( *this,
										   &t_adventure_frame::show_town_dialog ));
	m_town_list->set_map( *m_adventure_map );
	m_town_list->set_town_list( player.get_towns(), player.get_team() );
	m_town_list->attach( m_town_scrollbar );
	m_town_scrollbar->set_page_size( rect.height() / frame_rect.height() );

	// create army display
	t_screen_point    point;
	t_creature_array* army = 0;
	t_bitmap_layer const* layer;

	if (m_selected_army != 0)
		army = &m_selected_army->get_creatures();
	layer = m_interface_background->find( "army" );
	if (layer != 0)
	{
		point = layer->get_rect().top_left() - right_bar_bitmap->get_rect().top_left();
		m_army_display = new t_creature_array_window( point, army, 
													  t_creature_array_window::k_stacked_rows,
													  0, m_right_bar );
		m_army_display->set_select_handler( bound_handler( *this,
										    &t_adventure_frame::select_creature ) );
		m_army_display->set_double_click_handler( bound_handler( *this,
			                                      &t_adventure_frame::creature_double_click ));
	}
	
	// create day display
	m_day_scroll.init( m_interface_background->find( "day_scroll" )->get_rect().top_left() - origin,
		               m_adventure_map->get_day(), m_right_bar );
	select_army( m_selected_army );
	m_army_display->select_leader();

	// create army list
	rect = m_interface_background->find( "hero_list" )->get_rect();
	frame_rect = g_army_rings.get()->find( "army_frame" )->get_rect();
	rect.right = rect.left + frame_rect.width();
	m_army_list = new t_army_list_window( rect - origin, m_right_bar, false );
	m_army_list->set_select_handler( bound_handler( *this, &t_adventure_frame::select_army ) );
	m_army_list->set_double_click_handler(
		bound_handler( *this, &t_adventure_frame::show_army_dialog ) );
	m_army_list->set_army_array( player.get_armies() );
	m_army_list->attach( m_army_scrollbar );
	m_army_scrollbar->set_page_size( rect.height() / frame_rect.height() );
}

// ----------------------------------------------------
// toggle material display for 800x600 window
// ----------------------------------------------------
void t_adventure_frame::resources_bar_clicked( t_button* )
{
	m_resources_bar->set_visible(false);
	m_gold_bar->set_visible(true);
}

// ----------------------------------------------------
// toggle material display for 800x600 window
// ----------------------------------------------------
void t_adventure_frame::gold_bar_clicked( t_button* )
{
	m_resources_bar->set_visible(true);
	m_gold_bar->set_visible(false);
}

// ----------------------------------------------------
// frame window for adventure map
// select a creature
// ----------------------------------------------------
void t_adventure_frame::select_creature( t_creature_array_window* window, int slot )
{
	m_creature_detail.select_creature( window, slot );
	update_buttons();
}

// ----------------------------------------------------
// frame window for adventure map
// show army dialog
// ----------------------------------------------------
void t_adventure_frame::creature_double_click( t_creature_array_window* window, int slot )
{
	if (m_selected_army == 0 || window->get_army() != &m_selected_army->get_creatures())
		return;

	run_army_dialog( m_selected_army, NULL, slot );
}

// -------------------------------------------------------------------------------
// A helper for process_arriving_caravans(). Place armies arriving in towns
// owned by the current player into the garrison
// -------------------------------------------------------------------------------
void t_adventure_frame::process_arriving_caravans_move_to_garrisons()
{
	t_adventure_map &map = *get_map();
	t_player & player = map.get_current_player();
	int player_number = map.get_current_player_number();

	// Not a reference so that we can call t_player::remove( t_caravan * ) without
	// invalidating the iterator
	t_caravan_set caravans = player.get_caravans();
	
	t_caravan_set::iterator it;

	for ( it = caravans.begin(); it != caravans.end(); it++ )
	{
		assert( !(*it)->empty() );

		if ( !(*it)->has_arrived() )
			continue;

		t_town * destination = (*it)->get_destination();

		if ( destination->get_owner_number() == player_number )
		{
			if ( (*it)->add_caravan_to_army( *destination ) )
			{
				player.remove( *it );
				map.remove_caravan( *it );
		
				// Do nobility stuff
				destination->visit_town( destination );

				// Give bonuses & teach spells, but don't display messages
				destination->check_bonus_buildings( NULL, NULL );
			}
		}
	}
}


// -------------------------------------------------------------------------------
// Helper for process_arriving_caravans_generate_external_armies(). Attempt to place the caravan in an
// army outside the town
// -------------------------------------------------------------------------------
static bool place_outside_town( t_adventure_map & map, 
								t_caravan * caravan, t_town * destination, 
								int player_number,
								t_army_ptr & current_outside_army,
								bool can_form_new_army,
								bool & cannot_form_external_army,
								t_army_list & created_armies)
{
	bool handled = false;
	cannot_form_external_army = false;

	if ( current_outside_army.get() == NULL )
	{
		// Try to create a new army
		t_adv_map_point point;
		if ( can_form_new_army && destination->find_nearby_space( point, *caravan ) )
		{
			current_outside_army = new t_army( caravan ); // Transfer contents of caravan to new army
			current_outside_army->set_owner( player_number );
			current_outside_army->place( map, point );
			created_armies.push_back( current_outside_army );
			assert( caravan->empty() );
			handled = true;

		}
		else
		{
			cannot_form_external_army = true;
			return false;
		}
	}

	if ( !handled )
	{
		if ( can_combine( *caravan, *current_outside_army ) )
		{
			handled = caravan->add_caravan_to_army( *current_outside_army );
			assert( handled ); 
		}
	}

	return handled;
}

// -------------------------------------------------------------------------------
// A helper for process_arriving_caravans(). Place any arrived caravans in 
// external (adventure map) armies outside their towns.
// -------------------------------------------------------------------------------
void t_adventure_frame::process_arriving_caravans_generate_external_armies( t_town_list & dropped_in_external_army_for_foreign_town_list, 
																			int & dropped_in_external_army_for_foreign_count, 
																			t_town_list & dropped_in_external_army_for_own_town_list, 
																			int & dropped_in_external_army_for_own_count, 
																			t_army_list & created_armies )
{
	t_adventure_map &map = *get_map();
	int player_number = map.get_current_player_number();
	t_player & player = map.get_current_player();

	bool arrivals_still_pending = true; // Do we still have caravans arriving 
	bool all_towns_cannot_form_armies = false; // Are we sure no more external armies can be formed?

	dropped_in_external_army_for_foreign_count = 0;
	dropped_in_external_army_for_own_count = 0;

	while ( arrivals_still_pending && !all_towns_cannot_form_armies )
	{
		// Not a t_caravan_set reference to avoid problems when calling t_player::remove( t_caravan * )
		t_caravan_set caravans = player.get_caravans();

		t_caravan_set::iterator it;

		t_town * current_destination = NULL;

		t_army_ptr current_outside_army; 

		bool skip_town;

		bool added_to_external_army_list;

		arrivals_still_pending = false;
		all_towns_cannot_form_armies = true;

		t_town_list * dropped_in_external_army_town_list_ptr;
		int         * dropped_in_external_army_count_ptr;

		for ( it = caravans.begin(); it != caravans.end(); it++ )
		{
			assert( !(*it)->empty() );

			if ( !(*it)->has_arrived() )
				continue;

			// Conveniently, caravans are sorted by destination town in a t_caravan_set,
			// so all the caravans for the same destination come out together.
			if ( current_destination != (*it)->get_destination() )
			{
				// New town
				current_outside_army = NULL;
				skip_town = false;
				added_to_external_army_list = false;
				current_destination = (*it)->get_destination();

				if ( current_destination->get_owner_number() == player_number )
				{
					dropped_in_external_army_town_list_ptr = &dropped_in_external_army_for_own_town_list;
					dropped_in_external_army_count_ptr = &dropped_in_external_army_for_own_count;
				}
				else
				{
					dropped_in_external_army_town_list_ptr = &dropped_in_external_army_for_foreign_town_list;
					dropped_in_external_army_count_ptr = &dropped_in_external_army_for_foreign_count;
				}
			}

			if ( skip_town )
				continue;

			// Allow occupied towns to exceed 8 army limit
			bool can_create_new_army;
			if ( current_destination->get_owner_number() == player_number )
			{
				can_create_new_army = player.can_create_army();
			}
			else
			{
				can_create_new_army = true;
			}

			bool cannot_form_external_army;
			if ( place_outside_town( map, it->get(), current_destination, player_number,
									  current_outside_army, can_create_new_army, cannot_form_external_army, created_armies ) )
			{
				// Erase caravan
				player.remove( *it );
				map.remove_caravan( *it );
				(*dropped_in_external_army_count_ptr)++;
				
				if ( !added_to_external_army_list )
				{
					if ( std::find( dropped_in_external_army_town_list_ptr->begin(), dropped_in_external_army_town_list_ptr->end(), t_town_ptr( current_destination ) ) == dropped_in_external_army_town_list_ptr->end() )
						dropped_in_external_army_town_list_ptr->push_back( current_destination );

					added_to_external_army_list = true;
				}

				update_army( current_outside_army );
			}
			else
			{
				arrivals_still_pending = true;
			}

			if ( cannot_form_external_army )
			{
				skip_town = true;
			}
			else
			{
				all_towns_cannot_form_armies = false;
			}
		}
	}
}

// -------------------------------------------------------------------------------
// Helper for process_arriving_caravans(). Take all of the caravans left after
// we move what we can into garrisons & external armies -- the caravans which
// will be listed as "Arrived" -- and list the towns in the appropriate 
// list. WARNING: This function should make no change to the state of
// the caravan list, since it is called only for humans and not computer
// players
// -------------------------------------------------------------------------------
void t_adventure_frame::process_arriving_caravans_list_waiting_caravans( t_town_list & wait_in_own_town_list, int & wait_in_own_count, 
																	     t_town_list & wait_in_allied_town_list, int & wait_in_allied_count,
																		 t_town_list & wait_near_enemy_town_list, int & wait_near_enemy_count ) const
{
	t_adventure_map const &map = *get_map();
	t_player const & player = map.get_current_player();
	int player_number = map.get_current_player_number();

	t_caravan_set caravans = player.get_caravans();
	
	t_caravan_set::iterator it;

	t_town * current_destination = NULL;

	bool added_to_waiting_array;

	wait_in_own_count = 0;
	wait_in_allied_count = 0;
	wait_near_enemy_count = 0;

	t_town_list * town_list_ptr;
	int         * count_ptr;

	for ( it = caravans.begin(); it != caravans.end(); it++ )
	{
		assert( !(*it)->empty() );

		if ( !(*it)->has_arrived() )
			continue;

		// Conveniently, caravans are sorted by destination town in a t_caravan_set,
		// so all the caravans for the same destination come out together.
		if ( current_destination != (*it)->get_destination() )
		{
			// New town
			current_destination = (*it)->get_destination();
			added_to_waiting_array = false;

			if ( player_number == current_destination->get_owner_number() )
			{
				town_list_ptr = &wait_in_own_town_list;
				count_ptr = &wait_in_own_count;
			}
			else if ( same_team( &player, current_destination->get_owner() ) )
			{
				town_list_ptr = &wait_in_allied_town_list;
				count_ptr = &wait_in_allied_count;
			}
			else
			{
				town_list_ptr = &wait_near_enemy_town_list;
				count_ptr = &wait_near_enemy_count;
			}
		}

		if ( !added_to_waiting_array)
		{
			town_list_ptr->push_back( current_destination );
			added_to_waiting_array = true;
		}

		(*count_ptr)++;
	}
}

static t_external_string const k_caravan_arrived_occupied_singular( "caravan.arrived_occupied_singular" );
static t_external_string const k_caravan_arrived_occupied_plural_1_town( "caravan.arrived_occupied_plural_1_town" );
static t_external_string const k_caravan_arrived_occupied_plural_multiple_towns( "caravan.arrived_occupied_plural_multiple_towns" );
static t_external_string const k_caravan_arrival_separator( "caravan.arrival_separator" );
static t_external_string const k_caravan_arrived_occupied_by_ally_singular( "caravan.arrived_occupied_by_ally_singular" );
static t_external_string const k_caravan_arrived_occupied_by_ally_plural_1_town( "caravan.arrived_occupied_by_ally_plural_1_town" );
static t_external_string const k_caravan_arrived_occupied_by_ally_plural_multiple_towns( "caravan.arrived_occupied_by_ally_plural_multiple_towns" );
static t_external_string const k_caravan_arrived_full_dropped_singular( "caravan.arrived_full_dropped_singular" );
static t_external_string const k_caravan_arrived_full_dropped_plural_1_town( "caravan.arrived_full_dropped_plural_1_town" );
static t_external_string const k_caravan_arrived_full_dropped_plural_multiple_towns( "caravan.arrived_full_dropped_plural_multiple_towns" );
static t_external_string const k_caravan_arrived_full_singular( "caravan.arrived_full_singular" );
static t_external_string const k_caravan_arrived_full_plural_1_town( "caravan.arrived_full_plural_1_town" );
static t_external_string const k_caravan_arrived_full_plural_multiple_towns( "caravan.arrived_full_plural_multiple_towns" );
static t_external_string const k_caravan_failed_occupied_singular( "caravan.failed_occupied_singular" );
static t_external_string const k_caravan_failed_occupied_plural_1_town( "caravan.failed_occupied_plural_1_town" );
static t_external_string const k_caravan_failed_occupied_plural_multiple_towns( "caravan.failed_occupied_plural_multiple_towns" );

// -------------------------------------------------------------------------------
// Process the caravans that arrived for the current player
// -------------------------------------------------------------------------------
void t_adventure_frame::process_arriving_caravans( )
{
	t_counted_ptr<t_adventure_map> map = get_map();
	t_player & player = map->get_current_player();

	t_town_list dropped_in_external_army_for_foreign_town_list; // Towns where another player owned the towns so the caravans were turned into adventure map armies
	int         dropped_in_external_army_for_foreign_count;     // # of caravans this happened to
	t_town_list dropped_in_external_army_for_own_town_list;		// Towns where the garrison was full so the caravans were turned into adventure map armies
	int         dropped_in_external_army_for_own_count;			// # of caravans this happened to
	t_town_list wait_near_enemy_town_list;						// Towns where caravans arrived in enemy town and couldn't become adventure map army
	int			wait_near_enemy_count;							// # of caravans this happened to
	t_town_list wait_in_own_town_list;							// Towns where caravan arrived in own town but garrison was full
	int			wait_in_own_count;								// # of caravans this happened to
	t_town_list wait_in_allied_town_list;						// Towns where caravan arrived in allied town and could not form adventure map army
	int         wait_in_allied_count;							// # of caravans this happened to

	t_army_list created_armies;

	// First pass: Move any caravans that arrived in our own towns into caravans 
	process_arriving_caravans_move_to_garrisons();

	// Second pass: Create outside armies for any arrived caravans left after 1st pass
	// Continue until all caravans handled or we cannot continue to add outside armies
	// to any town
	process_arriving_caravans_generate_external_armies( dropped_in_external_army_for_foreign_town_list, dropped_in_external_army_for_foreign_count, 
														dropped_in_external_army_for_own_town_list, dropped_in_external_army_for_own_count,
														created_armies );

	
	// Don't need to display messages for computer
	if ( !player.is_computer() )
	{
		// Third pass: Generate name lists for any caravans still left after the 2nd pass.
		// These caravans will be left as "arrived" caravans
		process_arriving_caravans_list_waiting_caravans( wait_in_own_town_list, wait_in_own_count, 
														 wait_in_allied_town_list, wait_in_allied_count,
														 wait_near_enemy_town_list, wait_near_enemy_count );
		std::string caravan_text;

		if ( !dropped_in_external_army_for_foreign_town_list.empty() )
		{
			t_keyword_replacer replacer;
			int index;

			for ( index = 0; index < dropped_in_external_army_for_foreign_town_list.size(); index++ )
			{
				replacer.add_to_list( "%town_list", index + 1, dropped_in_external_army_for_foreign_town_list[index]->get_name() );
			}

			replacer.add_keyword( "%count", format_string( "%d", dropped_in_external_army_for_foreign_count ) );

			if ( dropped_in_external_army_for_foreign_count == 1 )
				caravan_text += replacer( k_caravan_arrived_occupied_singular );
			else if ( dropped_in_external_army_for_foreign_town_list.size() == 1 )
				caravan_text += replacer( k_caravan_arrived_occupied_plural_1_town );
			else
				caravan_text += replacer( k_caravan_arrived_occupied_plural_multiple_towns );
		}

		if ( !wait_near_enemy_town_list.empty() )
		{
			if ( !caravan_text.empty() )
			{
				caravan_text += k_caravan_arrival_separator;
			}

			t_keyword_replacer replacer;
			int index;

			for ( index = 0; index < wait_near_enemy_town_list.size(); index++ )
			{
				replacer.add_to_list( "%town_list", index + 1, wait_near_enemy_town_list[index]->get_name() );
			}

			replacer.add_keyword( "%count", format_string( "%d", wait_near_enemy_count ) );

			if ( wait_near_enemy_count == 1 )
				caravan_text += replacer( k_caravan_failed_occupied_singular );
			else if ( wait_near_enemy_town_list.size() == 1 )
				caravan_text += replacer( k_caravan_failed_occupied_plural_1_town );
			else
				caravan_text += replacer( k_caravan_failed_occupied_plural_multiple_towns );

		}

		if ( !dropped_in_external_army_for_own_town_list.empty() )
		{
			t_keyword_replacer replacer;
			int index;

			for ( index = 0; index < dropped_in_external_army_for_own_town_list.size(); index++ )
			{
				replacer.add_to_list( "%town_list", index + 1, dropped_in_external_army_for_own_town_list[index]->get_name() );
			}

			replacer.add_keyword( "%count", format_string( "%d", dropped_in_external_army_for_own_count ) );

			if ( dropped_in_external_army_for_own_count == 1 )
				caravan_text += replacer( k_caravan_arrived_full_dropped_singular );
			else if ( dropped_in_external_army_for_own_town_list.size() == 1 )
				caravan_text += replacer( k_caravan_arrived_full_dropped_plural_1_town );
			else
				caravan_text += replacer( k_caravan_arrived_full_dropped_plural_multiple_towns );
		}

		if ( !wait_in_own_town_list.empty() )
		{
			if ( !caravan_text.empty() )
			{
				caravan_text += k_caravan_arrival_separator;
			}

			t_keyword_replacer replacer;
			int index;

			for ( index = 0; index < wait_in_own_town_list.size(); index++ )
			{
				replacer.add_to_list( "%town_list", index + 1, wait_in_own_town_list[index]->get_name() );
			}

			replacer.add_keyword( "%count", format_string( "%d", wait_in_own_count ) );

			if ( wait_in_own_count == 1 )
				caravan_text += replacer( k_caravan_arrived_full_singular );
			else if ( wait_in_own_town_list.size() == 1 )
				caravan_text += replacer( k_caravan_arrived_full_plural_1_town );
			else
				caravan_text += replacer( k_caravan_arrived_full_plural_multiple_towns );
		}

		if ( !wait_in_allied_town_list.empty() )
		{
			if ( !caravan_text.empty() )
			{
				caravan_text += k_caravan_arrival_separator;
			}

			t_keyword_replacer replacer;
			int index;

			for ( index = 0; index < wait_in_allied_town_list.size(); index++ )
			{
				replacer.add_to_list( "%town_list", index + 1, wait_in_allied_town_list[index]->get_name() );
			}

			replacer.add_keyword( "%count", format_string( "%d", wait_in_allied_count ) );

			if ( wait_in_allied_count == 1 )
				caravan_text += replacer( k_caravan_arrived_occupied_by_ally_singular );
			else if ( wait_in_allied_town_list.size() == 1 )
				caravan_text += replacer( k_caravan_arrived_occupied_by_ally_plural_1_town );
			else
				caravan_text += replacer( k_caravan_arrived_occupied_by_ally_plural_multiple_towns );
		}

		if ( !caravan_text.empty() )
			ok_dialog( caravan_text, true );
	}

	// Trigger events if needed for new armies
	t_army_list::iterator army_iter;

	for ( army_iter = created_armies.begin(); army_iter != created_armies.end(); army_iter++ )
	{
		(*army_iter)->trigger_events();

		if ( map->is_game_over() )
			return;
	}
}

void t_adventure_frame::force_end_turn()
{
    // Expend all movement.  Windows need to be open at this point.
	t_player const& cur_player = m_adventure_map->get_current_player();
	if (!cur_player.is_computer())
    {
	    t_army_array const* army_list = cur_player.get_armies();
        for (int i=0; i<army_list->size(); i++)
        {
	        t_army* army_ptr = (*army_list)[i];
            army_ptr->expend_all_movement();
        }
    }

    end_turn_click( NULL );
}

// ----------------------------------------------------
// frame window for adventure map
// handle an end-of-turn button click
// ----------------------------------------------------
void t_adventure_frame::end_turn_click( t_button* )
{
	t_adventure_map_ptr	map = m_adventure_map;	// make sure this is counted ptr so it's not released if game is over
	t_window_ptr reference = this;

	///////////////////////////////////////////////////////
	//replay/multiplay functionality.

	map->increment_event_tick();
	map->record_replay_shroud();

	///////////////////////////////////////////////////////
	
	if ( !m_adventure_map_window->halt_movement() )
		return;
	m_adventure_map_window->clear_spell_targeter();

    // Should we remind player if he has movement left?
    if (army_movement_reminder())
    {
        int i;
    	t_player const& cur_player = m_adventure_map->get_current_player();
    	if (!cur_player.is_computer())
        {
    	    t_army_array const* army_list = cur_player.get_armies();
            bool    has_movement_left = false;

            // Check for remaining movement.
            for (i=0; i<army_list->size(); i++)
            {
    	        t_army* army_ptr = (*army_list)[i];
    		    if (!army_ptr->get_sleeping() && army_ptr->get_movement() > 0 && army_ptr->get_movement() >= army_ptr->get_next_step_cost())
                {
                    has_movement_left = true;
                    break;
                }
            }
       
            if (has_movement_left)
            {
                // Does player want to forgo movement?
                if (!(yes_no_dialog( k_text_movement_left )))
                    return;
            }
        }
    }

	if( m_end_turn_button )
		m_end_turn_button->set_visible( false );
	m_end_turn_animation_window->set_visible( true );
	m_end_turn_animation_window->set_frame( 0 );
	m_end_turn_animation_window->enable_animation( true );

	// fade out the active sounds list
	close_active_sounds();

	t_sound_cache music = get_music_playing();
	static t_sound_cache enemy_turn_music = "end_turn";
	play_music( enemy_turn_music );

	do_end_turn();

	play_music( music );
}

void t_adventure_frame::set_day( int day )
{
	m_day_scroll.new_day( day );
}

// ----------------------------------------------------
// basic loop for running a series of turns.
// ----------------------------------------------------
void t_adventure_frame::do_end_turn()
{
	while (!m_adventure_map->is_game_over())
	{
		m_adventure_map->get_current_player().on_end_turn();

		// Clear the previous players selections
		select_army( NULL );
		select_town( NULL );
		m_adventure_map->clear_path();
		m_adventure_map->clear_selection();

		reset_turn_time();

		m_adventure_map->set_next_player( this );

		if (m_adventure_map->is_game_over())
			return;

		t_player& player = m_adventure_map->get_current_player();

		player.on_begin_turn();

		if (player.is_computer())
		{
			process_arriving_caravans();
			m_adventure_map->process_timed_events( this );
			update();

			if (!m_adventure_map->is_game_over())
			{
				m_adventure_map->get_ai().do_turn( this );
			}

			if( get_enable_auto_play() )
				autosave_game();
		}
		else
		{
			///////////////////////////////////////////////////////
			//replay/multiplay functionality.
			
			//-clear the events before the local players turn in the event list.
			
			m_adventure_map->update_event_buffer(m_adventure_map->get_player_number());
			
			///////////////////////////////////////////////////////

			start_human_turn();
			if (m_adventure_map->is_game_over())
				return;
			autosave_game();
			break;
		}
	}
}

static t_external_string const k_victory_pending_plural( "victory_pending_plural.adventure_map" );
static t_external_string const k_victory_pending_singular( "victory_pending_singular.adventure_map" );
static t_external_string const k_defeat_pending_plural( "defeat_pending_plural.adventure_map" );
static t_external_string const k_defeat_pending_singular( "defeat_pending_singular.adventure_map" );

// ----------------------------------------------------
// frame window for adventure map
// extracted from end_turn_click above to allow
// games to handoff turns.  Not sure
// this is the right arrangment yet, but we'll see...
// ----------------------------------------------------
void t_adventure_frame::start_human_turn()
{
	t_player & player = m_adventure_map->get_player();

	m_material_display.set_player( &player );
	m_material_display_gold.set_player( &player );
	m_town_list->set_town_list( player.get_towns(), player.get_team() );
	m_army_list->set_army_array( player.get_armies() );
	clear_pending_messages();
	
	{
		if (m_adventure_map->is_hotseat())
		{
			t_player_info_hider hider( *this );
			ok_dialog( replace_keywords( k_text_players_turn, "%player_name", m_adventure_map->get_current_player().get_name() ), true );
		}
	
		select_first_item();
		update();
		refresh_path();

		if ( m_adventure_map->get_day() != 0 && ( ( m_adventure_map->get_day() % k_days_per_month ) == 0 ) )
		{
			std::string text = replace_keywords( k_new_month_message, "%creature", get_traits( m_adventure_map->get_previous_month_creature() ).name );
			ok_dialog( text, true, k_new_month_title );
		}
	}

	int winning_team = m_adventure_map->get_winning_team();
	if ( winning_team == m_adventure_map->get_current_player().get_team())
	{
		int victory_timer = m_adventure_map->get_victory_timer();
		if (victory_timer > 0)
		{
			if (victory_timer == 1)
				ok_dialog( k_victory_pending_singular );
			else
			{
				std::string text = replace_keywords( k_victory_pending_plural , "%days", format_string( "%d", victory_timer )); 
				ok_dialog( text );
			}
		}
		else
		{
			game_over( k_game_over_result_win, m_adventure_map->get_winning_team() );
			return;
		}
	} 
	else
	{
		if (winning_team != -1)
		{
			int victory_timer = m_adventure_map->get_victory_timer();
			if (victory_timer == 1)
				ok_dialog( k_defeat_pending_singular );
			else
			{
				std::string text = replace_keywords( k_defeat_pending_plural , "%days", format_string( "%d", victory_timer )); 
				ok_dialog( text );
			}
		}
	}

	m_adventure_map->process_timed_events( this );

	process_arriving_caravans();
	
	update();
}


// ----------------------------------------------------
// frame window for adventure map
// hourglassing flip ended, hide it and replace.
// ----------------------------------------------------
void t_adventure_frame::end_turn_animation_finished( t_window* animation )
{
	animation->set_visible( false );
	if( m_end_turn_button )
		m_end_turn_button->set_visible( true );
}


// -------------------------------------------------------------------------------
// Start a human controlled army moving on the map
// -------------------------------------------------------------------------------
void t_adventure_frame::start_army_moving( t_army* army )
{
	assert( army );

	if (army->get_path().empty() || army->get_movement() < army->get_next_step_cost()) 
		return;

	// make sure they are awake
	army->set_sleeping( false );

	// start army moving.
	m_adventure_map->clear_path();
	m_adventure_map->clear_selection();

	t_counted_ptr<t_army_mover> mover = new t_army_mover( m_adventure_map_window, army, true,
														  m_path_finder.get() );

	m_adventure_map_window->run_object_mover( mover, true );
}


// ----------------------------------------------------
// toggles going between underground and overground views
// ----------------------------------------------------
void t_adventure_frame::layer_view_click( t_button* button )
{
	// Toggle the visible level of the map
	set_view_level( 1 - m_adventure_map_window->get_view_level() );
}

// ----------------------------------------------------
// frame window for adventure map
// react to a resolution change
// ----------------------------------------------------
void t_adventure_frame::on_size_change( t_screen_rect const& rect )
{
	set_resolution( rect.width() );
}

// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
extern t_external_string const k_text_open_failure( "open_failure.dialog" );
t_external_string const        k_text_saving_label( "saving.dialog" );

// --------------------------------------------------------
// save a game
// --------------------------------------------------------
bool write_saved_game( t_window* parent, t_adventure_map* adventure_map, 
					   t_saved_combat* saved_combat )
{
	bool result = false;

	t_counted_ptr<t_dialog_save_game> dialog;

	dialog = new t_dialog_save_game( parent );
	if (!dialog->run_modal())
		return false;

	std::string  full_name = dialog->get_file_name();
	std::filebuf file;
	std::string  text;

	if (file.open( full_name.c_str(), std::ios::out | std::ios::binary ) == 0)
	{
		text = replace_keywords( k_text_open_failure, "%file_name", full_name );
		ok_dialog( text, true );
		return false;
	}

	adventure_map->clear_path();
	adventure_map->clear_selection();

	t_progress_bar_dialog*  progress_bar = new t_progress_bar_dialog( parent, k_text_saving_label );
	t_progress_handler*     handler = progress_bar->get_handler();
	t_deflate_filter		stream( file );

	t_game_application::set_cursor_visible( false );
	try
	{
		adventure_map->write( stream, handler, saved_combat );
		result = true;
	}
	catch(...)
	{
		ok_dialog( replace_keywords(k_text_open_failure,"%file", full_name), true );
	}

	progress_bar->close();
	t_game_application::set_cursor_visible( true );

	return result;
}

bool t_adventure_frame::save_game()
{
	t_counted_ptr<t_dialog_save_game> dialog;

	if ( m_adventure_map_window->get_object_mover() != 0 )
		return false;
	m_adventure_map_window->clear_spell_targeter();
	bool result = write_saved_game( this, m_adventure_map, 0 );
	refresh_path();
	return result;
}

void t_adventure_frame::save_handler()
{
	save_game();
}

// ----------------------------------------------------
// Auto save.
// ----------------------------------------------------
t_external_string const k_text_autosave_failure( "auto_save_failed.misc" );
t_external_string const k_text_autosave_this_turn( "auto_save_this_turn.misc" );
t_external_string const k_text_autosave_last_turn( "auto_save_last_turn.misc" );
t_external_string const k_text_autosave_label( "autosaving.dialog" );

void t_adventure_frame::autosave_game()
{
	std::string  save_directory = "games/";
	std::string  current_autosave_name = save_directory + k_text_autosave_this_turn.c_str();
	std::string  last_autosave_name = save_directory + k_text_autosave_last_turn.c_str();
	std::filebuf file;

	//t_directory_changer changer( save_directory );

    // Delete last auto save game.
    FILE* last_save_id;
	if (last_save_id = fopen ( last_autosave_name.c_str(), "r" ))
    {
        // File exists, close it and remove it.
        fclose (last_save_id);
        if ( ::remove ( last_autosave_name.c_str() ) )
        {
    		ok_dialog( k_text_autosave_failure, true );
    		return;
        }
    }

    // Rename autosave.h4s to lastsave.h4s.
    FILE* cur_save_id;
	if (cur_save_id = fopen ( current_autosave_name.c_str(), "r" ))
    {
        // File exists, close it and rename it.
        fclose (cur_save_id);
        if ( rename ( current_autosave_name.c_str(), last_autosave_name.c_str() ) )
        {
    		ok_dialog( k_text_autosave_failure, true );
    		return;
        }
    }

    // Open and save to autosave.h4s.
	if (file.open( current_autosave_name.c_str(), std::ios::out | std::ios::binary ) == 0)
    {
		ok_dialog( k_text_autosave_failure, true );
		return;
    }

	m_adventure_map->clear_path();
	m_adventure_map->clear_selection();
	t_progress_bar_dialog*  progress_bar = new t_progress_bar_dialog( this, k_text_autosave_label );
	t_progress_handler*     handler = progress_bar->get_handler();
	t_deflate_filter		stream( file );

	t_game_application::set_cursor_visible( false );
	m_adventure_map->write( stream, handler );
	progress_bar->close();
	t_game_application::set_cursor_visible( true );

	refresh_path();
}

// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
void t_adventure_frame::options()
{
	if ( m_adventure_map_window->get_object_mover() != 0 )
		return;
	m_adventure_map_window->clear_spell_targeter();

	t_counted_ptr<t_options_dialog> dialog = new t_options_dialog( this );

	if (!dialog->run_modal())
		return;

	switch (dialog->get_resolution())
	{
		case 800:
			::set_resolution( 800, 600, true );
			move( t_screen_rect(0,0,800,600) );
			break;

		case 1024:
			::set_resolution( 1024, 768, true );
			move( t_screen_rect( 0,0, 1024, 768 ));
			break;

		case 1280:
			::set_resolution( 1280, 1024, true );
			move( t_screen_rect( 0,0, 1280, 1024 ));
			break;
	}
	m_adventure_map_window->enable_animation(show_adventure_animations());
}

// ----------------------------------------------------
// frame window for adventure map
// get the currently selected creatures
// ----------------------------------------------------
t_creature_array* t_adventure_frame::get_selected_creatures() const
{
	if (m_in_army_mode)
	{
		if (m_selected_army != 0)
			return &m_selected_army->get_creatures();
	}
	else
	{
		if (m_selected_town != 0)
			return &m_selected_town->get_garrison();
	}

	return 0;
}

// ----------------------------------------------------
// frame window for adventure map
// get the slot number of the currently selected creature
// ----------------------------------------------------
int t_adventure_frame::get_selected_creature_slot() const
{
	if ( get_selected_creatures() == 0 )
		return -1;
	return m_army_display->get_selected_slot();
}

// ----------------------------------------------------
// frame window for adventure map
// get the currently selected creature
// ----------------------------------------------------
t_creature_stack* t_adventure_frame::get_selected_creature() const
{
	t_creature_array* army = get_selected_creatures();

	if (army == 0)
		return 0;

	int slot = m_army_display->get_selected_slot();

	if (slot < 0)
		return 0;

	return &(*army)[slot];
}

// ----------------------------------------------------
// frame window for adventure map
// update enabled / disabled states for buttons
// ----------------------------------------------------
void t_adventure_frame::update_buttons()
{
	// When the current player is local, we need to enable some buttons	
	if (m_selected_army != 0)
	{
		if( m_move_army_button )
			m_move_army_button->enable( true );

		t_creature_stack* creature = get_selected_creature();

		if( m_spell_button )
			m_spell_button->enable( creature != 0 && creature->can_cast_spells() );
	}
	else
	{
		if( m_spell_button )
			m_spell_button->enable( false );
		if( m_move_army_button )
			m_move_army_button->enable( false );
	}

	// I added these as conditional upon a human player.  Original behavior can be restored 
	// by changing the arguments to "enable" to 'true'.  SCR 1/3/02
	if( m_end_turn_button )
		m_end_turn_button->enable( !m_adventure_map->get_current_player().is_computer() );
	if (m_marketplace_button)
		m_marketplace_button->enable( !m_adventure_map->get_current_player().is_computer() );
	

	// update the under/over ground view buttons
	if(	m_adventure_map->get_num_levels() <= 1 )
	{
		if( m_surface_button )
			m_surface_button->set_visible( false );
		if( m_underground_button )
		{
			m_underground_button->set_visible( true );
			m_underground_button->enable( false );
		}
	} else
	{
		if( m_adventure_map_window->get_view_level() == 0 ) 
		{
			if( m_surface_button )
				m_surface_button->set_visible( false );
			if( m_underground_button )
				m_underground_button->set_visible( true );
		}
		else
		{
			if( m_surface_button )
				m_surface_button->set_visible( true );
			if( m_underground_button )
				m_underground_button->set_visible( false );
		}
	}
}

// ----------------------------------------------------
// frame window for adventure map
// update everything
// ----------------------------------------------------
void t_adventure_frame::update()
{
	if( !is_open() )
		return;

	set_team_view();

	update_towns();
	update_army();
	update_armies();
	update_buttons();
	update_funds();
	refresh_path();
}

// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
t_army* t_adventure_frame::get_selected_army() const
{
	if (m_in_army_mode)
		return m_selected_army;
	else
		return NULL;
}


// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
void t_adventure_frame::select_army( t_army* army )
{
	if (army && (army->get_owner() == 0 || army->get_owner()->is_computer()))
	{
		army = NULL;
	}

	if (get_selected_army() != army)
	{
		m_selected_army = army;
		if (m_army_list != 0)
			m_army_list->select_army( army );

		m_adventure_map_window->clear_spell_targeter();
		m_path_finder->set_army( army );
		refresh_path();

		m_adventure_map_window->update_cursor();
	}

	if (army != 0)
	{
		t_level_map_point_2d    point = army->get_position();
		t_screen_point screen_point = m_adventure_map->get_screen_point( point );

		m_adventure_map_window->set_view_level( point.level );
		m_adventure_map_window->center_view( screen_point );
		m_adventure_map->display_selection( army );
		set_music( m_adventure_map->get_tile( point ).get_terrain() );
		set_army_mode( true );

		t_level_map_point_2d const & sound_point = m_selected_army->get_creatures().get_position();
		update_active_sounds( sound_point, *get_map() );
	}
	else
	{
		m_adventure_map->clear_selection();
		if (m_army_display != 0)
			m_army_display->set_army( 0 );
	}

	update_buttons();
}

// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
void t_adventure_frame::select_town( t_town* town )
{
	if ( m_adventure_map_window->get_object_mover() != 0 )
		return;
	m_adventure_map_window->clear_spell_targeter();

	if (m_selected_town.get() != town)
	{
		m_selected_town = town;
		if (m_town_list != 0)
			m_town_list->select_town( town );
		m_adventure_map_window->update_cursor();
	}
	if (town != 0)
	{
		t_level_map_point_2d point = town->get_position();
		t_screen_point       screen_point = get_screen_point( *m_adventure_map, *town, point );

		m_adventure_map_window->set_view_level( point.level );
		m_adventure_map_window->center_view( screen_point );
		set_music( town->get_terrain() );
		set_army_mode( false );

		t_level_map_point_2d const & sound_point = town->get_position();
		update_active_sounds( sound_point, *get_map() );
	}
	else
	{
		if (m_army_display != 0)
			m_army_display->set_army( 0 );
	}
	m_adventure_map->clear_selection();
}


// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
void t_adventure_frame::show_army_dialog( t_army* army )
{
	if (army == 0)
		return;

	t_creature_stack const* leader = &army->get_creatures().get_leader();
	int			            slot;

	for (slot = 0; slot < t_creature_array::k_size; slot++)
		if (leader == &army->get_creatures()[slot])
			break;

	if ( m_adventure_map_window->get_object_mover() != 0 )
		return;
	m_adventure_map_window->clear_spell_targeter();

	run_army_dialog( army );
}

// ----------------------------------------------------
// frame window for adventure map
// Actually run the army dialog. All army dialog 
// requests should come through here
// ----------------------------------------------------
void t_adventure_frame::run_army_dialog( t_army * army, t_army * adjacent_army, int slot, 
										 bool trigger_events, t_handler enemy_attack_handler )
{
	t_counted_ptr< t_adventure_frame > ref = this;

	t_counted_ptr<t_army_dialog> dialog = new t_army_dialog( army, adjacent_army, this, slot );
	dialog->set_enemy_attack_handler( enemy_attack_handler );

	dialog->run_modal();

	if ( get_map()->is_game_over() )
		return;

	update_army();
	update_armies();

	if ( trigger_events )
		dialog->trigger_events();
}

// ----------------------------------------------------
// frame window for adventure map
// Check ALL of the local player's armies to see if
// they need to trigger events. Normally called some
// time after run_army_dialog() with trigger_events
// as false
// ----------------------------------------------------
void t_adventure_frame::check_for_event_triggers()
{
	t_counted_ptr< t_adventure_map > map = get_map();

	if ( map->is_game_over() )
		return;

	t_army_array_ptr armies = get_map()->get_player().get_armies();

	t_army_array::iterator it;

	for ( it = armies->begin(); it != armies->end(); it++ )
	{
		(*it)->trigger_events();

		if ( map->is_game_over() )
			return;
	}
}


// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
void t_adventure_frame::do_town_dialog( t_town* town, t_army* army )
{
	if (town == 0)
		return;

	if ( m_adventure_map_window->get_object_mover() != 0 )
		return;
	m_adventure_map_window->clear_spell_targeter();

	m_allow_scrolling = false;

	t_counted_ptr<t_town_window> dialog = new t_town_window( town, army, this );

	m_adventure_map_window->enable_animation( false );
	
	dialog->run_modal();

	m_adventure_map_window->enable_animation( show_adventure_animations() );
	update_towns();
	update_army();
	m_allow_scrolling = true;

	// turn back on appropriate map sounds
	bool is_computer = false;
	if( army )
	{
		t_player * owner = army->get_owner();
		is_computer = owner && owner->is_computer();
	}

	if( m_selected_army && !is_computer )
	{
		t_level_map_point_2d const & sound_point = m_selected_army->get_creatures().get_position();
		update_active_sounds( sound_point, *get_map() );
	}

	dialog->trigger_temporary_army_events();

}

// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
void t_adventure_frame::show_town_dialog( t_town* town )
{
	do_town_dialog( town, 0 );
}

// ----------------------------------------------------
// frame window for adventure map
// force army display to update - it may have changed
// ----------------------------------------------------
void t_adventure_frame::update_army()
{
	if( !is_open() )
		return;

	if (m_army_display != 0)
	{
		m_army_display->update();
		if (m_army_display->get_selected_slot() < 0)
			m_army_display->select_leader();
		else
			m_creature_detail.select_creature( m_army_display, m_army_display->get_selected_slot() );
	}
}

// ----------------------------------------------------
// frame window for adventure map
// force army list display to update - it may have changed
// ----------------------------------------------------
void t_adventure_frame::update_armies()
{
	if (m_army_list != 0)
		m_army_list->update();
}

// ----------------------------------------------------
// frame window for adventure map
// force town list display to update
// ----------------------------------------------------
void t_adventure_frame::update_towns()
{
	if (m_town_list != 0)
		m_town_list->update();
}

// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
static t_external_string const k_ask_main_menu( "confirm_exit.adventure_frame" );
void t_adventure_frame::main_menu()
{
	if ( m_adventure_map_window->get_object_mover() != 0 )
		return;

	m_adventure_map_window->clear_spell_targeter();

	if( !get_map()->is_game_over() )
	{
		if (!yes_no_dialog( k_ask_main_menu ))
			return;
	}

	// fade out the active sounds list
	close_active_sounds();

	// Save the parent window since close destroys "this" internally
	t_window_ptr parent_window = get_parent();	

	close();

	t_main_menu* window = new t_main_menu( parent_window );
}

// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
void t_adventure_frame::do_quit( t_button* )
{
	t_game_application::exit(0);
}

// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
void t_adventure_frame::do_save_and_quit( t_button* )
{
	g_quit_dialog->close();
	if (save_game())
		do_quit(0);
}

// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
extern t_button_cache g_large_button;

void t_adventure_frame::quit()
{
	if ( m_adventure_map_window->get_object_mover() != 0 )
		return;
	m_adventure_map_window->clear_spell_targeter();

	// Create the dialog
	t_help_block const&     help = get_help_block( "adventure_map" );
	g_quit_dialog = new t_basic_dialog;

	// Add the quit button
	t_button* quit_button = new t_button( g_large_button.get(), t_screen_point(0,0), g_quit_dialog, k_text_quit_on_quit );
	quit_button->set_click_handler( bound_handler( *this, &t_adventure_frame::do_quit ) );
    set_help( quit_button, help, "quit" );
	g_quit_dialog->add_button( quit_button );

	// Add the save and quit button
	t_button* save_button = new t_button( g_large_button.get(), t_screen_point(0,0), g_quit_dialog, k_text_save_on_quit );
	save_button->set_click_handler( bound_handler( *this, &t_adventure_frame::do_save_and_quit ) );
    set_help( save_button, help, "save_on_quit" );
	g_quit_dialog->add_button( save_button );

	// Add cancel button
	t_button* cancel_button = new t_button( g_large_button.get(), t_screen_point(0,0), g_quit_dialog, k_text_cancel_on_quit );
	g_quit_dialog->add_close_button( cancel_button, 0 );
    set_help( cancel_button, help, "cancel_quit" );

	g_quit_dialog->set_title( k_text_quit );
	g_quit_dialog->open();

	g_quit_dialog->run_modal();
}

// ----------------------------------------------------
// free experience cheat
// ----------------------------------------------------
void free_experience_cheat( t_creature_array& creatures, int slot, t_adventure_map const * map, t_window* parent )
{
	t_hero* hero = creatures[slot].get_hero();

	if (hero == 0)
		return;

	int new_level = hero->get_level() + 1;
	int experience = hero->get_experience( new_level );

	hero->add_experience( experience - hero->get_experience(), map, creatures.get_owner(), parent );
}

void t_adventure_frame::free_experience()
{
	if ( m_adventure_map_window->get_object_mover() != 0 )
		return;
	m_adventure_map_window->clear_spell_targeter();

	free_experience_cheat( m_selected_army->get_creatures(), m_army_display->get_selected_slot(),
		                   m_adventure_map.get(), this );
}

// ----------------------------------------------------
// new skill cheat
// ----------------------------------------------------
typedef std::pair< t_army *, t_hero * > t_army_hero_pair;
static void execute_learn_skill_cheat( t_army_hero_pair army_hero_pair, t_skill skill )
{
	t_hero*								 hero = army_hero_pair.second;
	std::vector<t_skill>::const_iterator index;
	std::string                          text;
	std::list<t_skill>                   skill_stack;
	bool								 first = true;

	skill_stack.push_back( skill );
	while (!skill_stack.empty())
	{
		skill = skill_stack.back();
		skill_stack.pop_back();
		if (hero->get_skill( skill.skill ) >= skill.level)
			continue;

		std::vector<t_skill> const&	requirements = get_requirements( skill );

		hero->learn_skill( skill, true );
		for (index = requirements.begin(); index != requirements.end(); index++)
		{
			if (hero->get_skill( index->skill ) < index->level)
				skill_stack.push_back( *index );
		}
		if (!first)
			text = ", " + text;
		text = get_name( skill ) + text;
		first = false;
	}
	text = " learned " + text;
	text = hero->get_name() + text;
	ok_dialog( text, true );
	hero->update_class( true );

	army_hero_pair.first->update_state();
}

// ----------------------------------------------------
// new skill cheat
// ----------------------------------------------------
static std::string get_skill_name( t_skill_type skill )
{
	std::string result = get_name( t_skill( skill, k_mastery_basic ));

	return result.substr( 6 );
}

// ----------------------------------------------------
// new skill cheat
// ----------------------------------------------------
static void choose_skill_level_cheat( t_army_hero_pair army_hero_pair, t_skill_type skill, t_window* parent )
{
	t_hero*				 hero = army_hero_pair.second;
	t_handler_1<t_skill> base_handler;
	t_handler            handler;
	t_skill_mastery      level;
	t_counted_ptr<t_scroll_menu> menu = new t_scroll_menu( parent );

	base_handler = add_1st_argument( function_2_handler( execute_learn_skill_cheat ),
		                             army_hero_pair );

	for (level = t_skill_mastery( hero->get_skill( skill ) + 1 );
		 level < k_mastery_count; enum_incr( level ))
	{
		handler = add_argument( base_handler, t_skill( skill, level ) );
		menu->add_item( get_name( t_skill( skill, level ) ), handler );
	}
	menu->open( get_mouse_position( parent ));
}

// ----------------------------------------------------
// new skill cheat
// ----------------------------------------------------
static void choose_skill_type_cheat( t_army_hero_pair army_hero_pair, t_skill_type primary, t_window* parent )
{
	t_hero*				 hero = army_hero_pair.second;
	t_skill_type	     skill;
	t_handler_1<t_skill_type> base_handler;
	t_handler            handler;
	t_counted_ptr<t_scroll_menu> menu = new t_scroll_menu( parent );
	int							 count = 0;

	base_handler = add_2nd_argument( add_1st_argument( function_3_handler( choose_skill_level_cheat ),
		                             army_hero_pair ), parent );

	for (skill = t_skill_type(0); skill < k_skill_count; enum_incr(skill))
	{
		if (hero->get_skill( skill ) < k_mastery_grand_master 
			&& get_primary_skill( skill ) == primary )
		{
			handler = add_argument( base_handler, skill );
			menu->add_item( get_skill_name( skill ), handler );
			count++;
		}
	}
	if (count == 1)
		handler();
	else
		menu->open( get_mouse_position( parent ));
}


// ----------------------------------------------------
// new skill cheat
// ----------------------------------------------------
static bool possible_skill_cheat( t_hero* hero, t_skill_type primary )
{
	t_skill_type	     skill;

	if (hero->get_skill( primary ) == k_mastery_none
		&& hero->get_primary_skill_count() >= k_primary_skill_limit)
		return false;
	for (skill = t_skill_type(0); skill < k_skill_count; enum_incr(skill))
	{
		if (hero->get_skill( skill ) < k_mastery_grand_master 
			&& get_primary_skill( skill ) == primary )
			return true;
	}
	return false;
}

// ----------------------------------------------------
// new skill cheat
// ----------------------------------------------------
void learn_skill_cheat( t_army* army, int slot, t_window* parent )
{
	t_hero* hero = (*army)[slot].get_hero();

	if (hero == 0)
		return;

	t_handler_1<t_skill_type> base_handler;
	t_handler                 handler;

	base_handler = add_2nd_argument( add_1st_argument( 
									 function_3_handler( choose_skill_type_cheat ), std::make_pair( army, hero ) ), parent );

	t_counted_ptr<t_scroll_menu> menu = new t_scroll_menu( parent );
	int							 count = 0;

	if (possible_skill_cheat( hero, k_skill_tactics ))
	{
		handler = add_argument( base_handler, k_skill_tactics );
		menu->add_item( "Tactics", handler );
		count++;
	}
	if (possible_skill_cheat( hero, k_skill_combat_defense ))
	{
		handler = add_argument( base_handler, k_skill_combat_defense );
		menu->add_item( "Combat", handler );
		count++;
	}
	if (possible_skill_cheat( hero, k_skill_scouting ))
	{
		handler = add_argument( base_handler, k_skill_scouting );
		menu->add_item( "Scouting", handler );
		count++;
	}
	if (possible_skill_cheat( hero, k_skill_nobility ))
	{
		handler = add_argument( base_handler, k_skill_nobility );
		menu->add_item( "Nobility", handler );
		count++;
	}
	if (possible_skill_cheat( hero, k_skill_life_magic ))
	{
		handler = add_argument( base_handler, k_skill_life_magic );
		menu->add_item( "Life", handler );
		count++;
	}
	if (possible_skill_cheat( hero, k_skill_order_magic ))
	{
		handler = add_argument( base_handler, k_skill_order_magic );
		menu->add_item( "Order", handler );
		count++;
	}
	if (possible_skill_cheat( hero, k_skill_death_magic ))
	{
		handler = add_argument( base_handler, k_skill_death_magic );
		menu->add_item( "Death", handler );
		count++;
	}
	if (possible_skill_cheat( hero, k_skill_chaos_magic ))
	{
		handler = add_argument( base_handler, k_skill_chaos_magic );
		menu->add_item( "Chaos", handler );
		count++;
	}
	if (possible_skill_cheat( hero, k_skill_nature_magic ))
	{
		handler = add_argument( base_handler, k_skill_nature_magic );
		menu->add_item( "Nature", handler );
		count++;
	}
	if (count == 0)
	{
		ok_dialog( hero->get_name() + " can learn no skills", true );
		return;
	}
	if (count == 1)
		handler();
	else
		menu->open( get_mouse_position( parent ));
}

void t_adventure_frame::cheat_learn_skill()
{
	if ( m_adventure_map_window->get_object_mover() != 0 )
		return;
	m_adventure_map_window->clear_spell_targeter();

	learn_skill_cheat( m_selected_army, m_army_display->get_selected_slot(),
		                   this );
}

// ----------------------------------------------------
// learn spells cheat
// ----------------------------------------------------
void learn_spells_cheat( t_creature_array& creatures, int slot )
{
	t_hero* hero = creatures[slot].get_hero();

	if (hero == 0)
		return;

	hero->learn_all_spells_cheat();
	hero->set_spell_points( 1000 );
}

// ----------------------------------------------------
// learn spells cheat
// ----------------------------------------------------
void t_adventure_frame::learn_spells_cheat()
{
	if (m_selected_army == 0)
		return;
	::learn_spells_cheat( m_selected_army->get_creatures(), m_army_display->get_selected_slot() );
}

// ----------------------------------------------------
// maximum luck cheat
// ----------------------------------------------------
/*
void t_adventure_frame::get_lucky_cheat()
{
	if (m_selected_army == 0)
		return;

	t_hero* hero = m_selected_army->get_creatures()[m_army_display->get_selected_slot()].get_hero();

	if (hero == 0)
		return;

//	hero->
}
*/


// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------

static t_external_string const k_text_scenario_information( "scenario_information" );
static t_external_string const k_text_kingdom_overview( "kingdom_overview" );
static t_external_string const k_text_find_hero( "find_hero" );
static t_external_string const k_text_quests( "quests" );
extern t_external_string const k_text_marketplace( "marketplace" );
static t_external_string const k_text_thieves_guild( "thieves_guild" );
static t_external_string const k_text_trade( "trade" );
static t_external_string const k_text_view_world( "view_world" );
static t_external_string const k_text_view_puzzle( "view_puzzle" );
static t_external_string const k_text_dig_treasure( "dig_treasure" );
static t_external_string const k_text_replay_turn( "replay_turn" );
static t_external_string const k_text_view_caravans( "view_caravans" );
static t_external_string const k_text_quest_log_help( "view_quests.misc" );
static t_external_string const k_text_marketplace_help( "trade_resources.misc" );
static t_external_string const k_text_thieves_guild_help( "thieves_guild_help.misc" );
static t_external_string const k_text_trade_help( "trade_help.misc" );
static t_external_string const k_text_puzzle_help( "puzzle_help.misc" );
static t_external_string const k_text_dig_help( "dig_help.misc" );
static t_external_string const k_text_replay_turn_help( "replay_turn_help.misc" );

void t_adventure_frame::game_menu( t_button* button )
{
	if ( m_adventure_map_window->get_object_mover() != 0 )
		return;
	m_adventure_map_window->clear_spell_targeter();

	t_scroll_menu* menu = new t_scroll_menu( this );

	menu->add_item( k_text_scenario_information, bound_handler( *this, &t_adventure_frame::scenario_info ));
	menu->add_item( k_text_kingdom_overview, bound_handler( *this, &t_adventure_frame::kingdom_overview ));
	menu->add_item( k_text_quests,  bound_handler( *this, &t_adventure_frame::quest_log_window ), 
					k_text_quest_log_help );
	menu->add_item( k_text_marketplace, bound_handler( *this, &t_adventure_frame::marketplace ),
                    k_text_marketplace_help );
		                 
	menu->add_item( k_text_thieves_guild, bound_handler( *this, &t_adventure_frame::thieves_guild ),
                    k_text_thieves_guild_help );
	menu->add_item( k_text_trade,  bound_handler( *this, &t_adventure_frame::kingdom_trade ), 
					k_text_trade_help );
	menu->add_item( k_text_view_world, bound_handler( *this, &t_adventure_frame::view_world ) );
	menu->add_item( k_text_view_puzzle,   bound_handler( *this, &t_adventure_frame::puzzle_window ),
                    k_text_puzzle_help );
	menu->add_item( k_text_dig_treasure, bound_handler( *this, &t_adventure_frame::dig ),
                    k_text_dig_help );
	menu->add_item( k_text_view_caravans, bound_handler( *this, &t_adventure_frame::view_caravan ) );
	menu->add_item( k_text_replay_turn,   bound_handler( *this, &t_adventure_frame::replay_turn ),
                    k_text_replay_turn_help );	
	if (show_cheat_menus())
	{
		if (m_selected_army != 0)
		{
			menu->add_item( "Unlimited Move", 
							 bound_handler( *this, &t_adventure_frame::unlimited_move ),
							 "Get Unlimited Movement" );

			int selected_slot = m_army_display->get_selected_slot();
			if (selected_slot != -1)
			{
				t_hero* hero = m_selected_army->get_creatures()[selected_slot].get_hero();

				if (hero != 0)
					menu->add_item( "Increase Level", 
						bound_handler( *this, &t_adventure_frame::free_experience ),
									   "Gain a level of experience" );
			}
		}
	}
	menu->open( to_client( button->get_screen_rect() ).top_left() );
	
}

// ----------------------------------------------------
// frame window for adventure map
// ----------------------------------------------------
void t_adventure_frame::unlimited_move()
{
	if (m_selected_army == 0)
		return;
	m_selected_army->change_movement( 1000000 );
	update_armies();
	refresh_path();
}

t_text_window*		g_text;

// ----------------------------------------------------
// attachs the replay adventure map to the various windows
// of the adventure frame
// ----------------------------------------------------
bool t_adventure_frame::attach_replay_adventure_map( )
{	
	//m_adventure_normal_map holds onto the normal map while were in replay mode.

	if (m_in_replay_mode == true) 
		return true;

	select_army(NULL);
	select_town(NULL);
	
	m_adventure_normal_map = m_adventure_map;
	m_adventure_map = m_adventure_replay_map;

	initialize();

	m_in_replay_mode = true;

	t_screen_rect rect(0,0,200,200);

	t_pixel_24    color(0,0,0);
	t_pixel_24    drop_color(200,200,200);

	m_replay_text				= new t_text_window( get_font( rect.height() ), rect, this, "Replay", color);

	m_replay_text->set_center_horizontal(true);
	m_replay_text->set_center_vertical(true);
	m_replay_text->set_drop_shadow(true,drop_color);

	return true;
}

// ----------------------------------------------------
// attachs the normal adventure map to the various windows
// of the adventure frame
// ----------------------------------------------------
bool t_adventure_frame::attach_normal_adventure_map( )
{
	if (m_in_replay_mode == false) 
		return true;

	select_army(NULL);
	select_town(NULL);

	m_adventure_map = m_adventure_normal_map;
	m_adventure_normal_map = NULL;

	initialize();

	m_in_replay_mode = false;
	
	if (m_replay_text!=NULL)
	{
		m_replay_text->close();
		m_replay_text = NULL;
	}

	return true;
}

// ----------------------------------------------------
// frame window for adventure map
// create a new army from a template
// ----------------------------------------------------
static void require_water_filter( t_level_map_point_2d const & point, bool & filter_out, t_adventure_map const * map )
{
	assert( map );

	if ( !map->is_ocean( point ) )
		filter_out = true;
}

static void disallow_water_filter( t_level_map_point_2d const & point, bool & filter_out, t_adventure_map const * map )
{
	assert( map );

	if ( !map->is_land( point ) )
		filter_out = true;
}

t_army* t_adventure_frame::create_army( t_adventure_object* source, t_army* army, t_army* temp_army )
{
	if (army == 0)
		return 0;

	if (army == temp_army)
	{
		if (army->get_creatures().empty())
			return 0;

		t_adv_map_point      point;
		if (	!source->find_adjacent_space( point, *army )
			&&	!source->find_nearby_space( point, *army ) )
		{
			assert( false );	// Why couldn't we place this army?
			return 0;
		}

		army = new t_army( temp_army );
		army->update_state();

		army->place( *m_adventure_map, point );
		update_armies();
		if (!army->is_graveyard() && army->get_owner() != NULL && 
			!army->get_owner()->is_computer()) 
			select_army( army );
	} 
	else 
	{
		if (!update_army( army ))
			return 0;
	}

	return army;
}

// ----------------------------------------------------
// frame window for adventure map
// destroy an empty army
// ----------------------------------------------------
void t_adventure_frame::destroy_army( t_army_ptr army )
{
	// must delete adjacent army, it's empty now.
	if (army == m_selected_army)
		select_army( 0 );
	army->destroy();
	m_path_finder->clear();
	update();
}

// ----------------------------------------------------
// frame window for adventure map
// check if army needs to be destroyed
// ----------------------------------------------------
bool t_adventure_frame::update_army( t_army* army )
{
	bool is_empty = army->get_creatures().empty();

	if (!is_empty || army->is_boat())
	{
		// Populated armies or boats (even if empty)
		army->update_state();
		if (army == m_selected_army && (army->is_graveyard() || is_empty))
			select_army( 0 );
		update();
		return true;
	} else {
		// Empty land armies
		destroy_army( army );
		return false;
	}
}

// ----------------------------------------------------
// frame window for adventure map
// update display of path
// ----------------------------------------------------
void t_adventure_frame::refresh_path()
{
	if (m_selected_army != 0)
		m_adventure_map->display_selection( m_selected_army );

	if (m_selected_army == 0 || m_selected_army->get_destination().row < 0
		|| get_map_window()->get_object_mover() != 0)
	{
		m_adventure_map->clear_path();
		update_buttons();
		return;
	}

    if (!(show_move_path()))
        return;

	t_adventure_path path;

	if (!m_path_finder->get_path( m_selected_army->get_destination(), path ))
	{
		m_selected_army->set_path( path );
		m_adventure_map->clear_path();
		update_buttons();
		return;
	}
	m_selected_army->set_path( path );
	m_adventure_map->display_path( path, m_selected_army->get_movement() );
	update_buttons();
}


// ----------------------------------------------------
// create creatures via cheat
// ----------------------------------------------------
void t_adventure_frame::replay_turn()
{
	//PDL::
	// -replay turn creates a 2nd adventure map using the in memory save game of the current maps
	//		current turn
	// -rollsbacks the replay map
	// -from the stored events replay the events on the 2nd adv_map until done, or the user escapes from
	//		the replay turn.
	
	select_army(NULL);
	select_town(NULL);
	
	////////////////////////////////////////////////////////////////////

	t_progress_bar_dialog*  progress_bar = new t_progress_bar_dialog( this );
	t_progress_handler*     handler = progress_bar->get_handler();

	t_game_application::set_cursor_visible( false );

	m_adventure_replay_map = m_adventure_map->create_replay_map( handler );

	progress_bar->close();

	t_game_application::set_cursor_visible( true );
	
	////////////////////////////////////////////////////////////////////

	if (m_adventure_replay_map!=NULL)
	{
		attach_replay_adventure_map( );
		m_adventure_replay_map->start_event_playback();
	}
	
	// override all the game's input
	// any mouse will abort the replay
	m_replay_input_handler.reset( new t_override_input(true) );
	
	t_handler cancel_handler = bound_handler( *this, &t_adventure_frame::replay_turn_finish );
	m_replay_input_handler->set_input_handler( cancel_handler );
}

// ----------------------------------------------------
// replay_turn_finish : cleans up replay map and reset variables
// ----------------------------------------------------
void t_adventure_frame::replay_turn_finish()
{
	if (m_in_replay_mode && m_adventure_replay_map != NULL)
	{
		m_adventure_replay_map->stop_event_playback();
		
		attach_normal_adventure_map( );
		
		m_adventure_replay_map = NULL;
		m_replay_input_handler.reset(NULL);
	}
}

// ----------------------------------------------------
// create creatures via cheat
// ----------------------------------------------------
bool create_creature_cheat( int id, t_creature_array& army )
{
	static int const k_ids[][2] =
	{
		{ k_id_cheat_create_peasants,		k_peasant },
		{ k_id_cheat_create_crossbowmen,	k_crossbowman },
		{ k_id_cheat_create_squires,		k_squire },
		{ k_id_cheat_create_ballistae,		k_ballista },
		{ k_id_cheat_create_pikemen,		k_pikeman },
		{ k_id_cheat_create_crusaders,		k_crusader },
		{ k_id_cheat_create_monks,			k_monk },
        { k_id_cheat_create_angels,			k_angel },
		{ k_id_cheat_create_champions,		k_champion },
		{ k_id_cheat_create_dwarves,		k_dwarf },
		{ k_id_cheat_create_halflings,		k_halfling },
		{ k_id_cheat_create_golems,			k_gold_golem },
		{ k_id_cheat_create_magi,			k_mage },
		{ k_id_cheat_create_genies,			k_genie },
		{ k_id_cheat_create_nagas,			k_naga },
		{ k_id_cheat_create_dragon_golems,	k_dragon_golem },
		{ k_id_cheat_create_titans,			k_titan },
		{ k_id_cheat_create_imps,			k_imp },
		{ k_id_cheat_create_skeletons,		k_skeleton },
		{ k_id_cheat_create_zombies,		k_zombie },
		{ k_id_cheat_create_cerberi,		k_cerberus },
		{ k_id_cheat_create_gargoyles,		k_gargoyle },
		{ k_id_cheat_create_ghosts,			k_ghost },
		{ k_id_cheat_create_mummies,		k_mummy },
		{ k_id_cheat_create_demons,			k_ice_demon },
		{ k_id_cheat_create_vampires,		k_vampire },
		{ k_id_cheat_create_venom_spawn,	k_venom_spawn },
		{ k_id_cheat_create_devils,			k_devil },
		{ k_id_cheat_create_bone_dragons,	k_bone_dragon },
		{ k_id_cheat_create_bandits,		k_bandit },
		{ k_id_cheat_create_orcs,			k_orc },
		{ k_id_cheat_create_pirates,		k_pirate },
		{ k_id_cheat_create_troglodytes,	k_troglodyte },
		{ k_id_cheat_create_beholders,		k_beholder },
		{ k_id_cheat_create_medusae,		k_medusa },
		{ k_id_cheat_create_minotaurs,		k_minotaur },
		{ k_id_cheat_create_trolls,			k_troll },
		{ k_id_cheat_create_efreeti,		k_efreet },
		{ k_id_cheat_create_nightmares,		k_nightmare },
		{ k_id_cheat_create_black_dragons,	k_black_dragon },
		{ k_id_cheat_create_hydras,			k_hydra },
		{ k_id_cheat_create_leprechauns,	k_leprechaun },
		{ k_id_cheat_create_sprites,		k_sprite },
		{ k_id_cheat_create_wolves,			k_wolf },
        { k_id_cheat_create_air_elementals,	k_air_elemental },
		{ k_id_cheat_create_earth_elementals,	k_earth_elemental },
		{ k_id_cheat_create_elves,				k_elf },
		{ k_id_cheat_create_fire_elementals,	k_fire_elemental },
		{ k_id_cheat_create_satyrs,				k_satyr },
		{ k_id_cheat_create_water_elementals,	k_water_elemental },
		{ k_id_cheat_create_white_tigers,		k_white_tiger },
		{ k_id_cheat_create_griffins,			k_griffin },
		{ k_id_cheat_create_unicorns,			k_unicorn },
		{ k_id_cheat_create_faerie_dragons,		k_faerie_dragon },
		{ k_id_cheat_create_mantises,			k_mantis },
		{ k_id_cheat_create_phoenixes,			k_phoenix },
		{ k_id_cheat_create_berserkers,			k_berserker },
		{ k_id_cheat_create_centaurs,			k_centaur },
		{ k_id_cheat_create_harpies,			k_harpy },
		{ k_id_cheat_create_mermaids,			k_mermaid },
		{ k_id_cheat_create_nomads,				k_nomad },
        { k_id_cheat_create_cyclopes,			k_cyclops },
		{ k_id_cheat_create_ogre_magi,			k_ogre_mage },
		{ k_id_cheat_create_behemoths,			k_behemoth },
		{ k_id_cheat_create_sea_monsters,		k_sea_monster },
		{ k_id_cheat_create_thunderbirds,		k_thunderbird },
	};

	int i;

	for (i = 0; i < ELEMENTS_OF( k_ids ); i++)
	{
		if (k_ids[i][0] == id)
		{
			army.add( t_creature_type(k_ids[i][1]), 20 );
			return true;
		}
	}
	return false;
}


// ----------------------------------------------------
// create artifact cheat
// ----------------------------------------------------
bool create_artifact_cheat( int id, t_artifact& artifact )
{
	switch (id)
	{
		case k_id_cheat_create_leather:
			artifact = get_default_artifact( k_artifact_leather_armor );
			return true;

		case k_id_cheat_create_chainmail: 
			artifact = get_default_artifact( k_artifact_chainmail );
			return true;

		case k_id_cheat_create_elven_chainmail: 
			artifact = get_default_artifact( k_artifact_elven_chainmail );
			return true;

		case k_id_cheat_create_plate_mail:
			artifact = get_default_artifact( k_artifact_plate_mail );
			return true;

		case k_id_cheat_create_shield:
			artifact = get_default_artifact( k_artifact_shield );
			return true;

		case k_id_cheat_create_crossbow:
			artifact = get_default_artifact( k_artifact_crossbow );
			return true;

		case k_id_cheat_create_longbow:
			artifact = get_default_artifact( k_artifact_longbow );
			return true;

		case k_id_cheat_create_mage_staff:
			artifact = get_default_artifact( k_artifact_mages_staff );
			return true;

		case k_id_cheat_create_axe:
			artifact = get_default_artifact( k_artifact_axe );
			return true;

		case k_id_cheat_create_longsword:
			artifact = get_default_artifact( k_artifact_longsword );
			return true;

		case k_id_cheat_create_greatsword:
			artifact = get_default_artifact( k_artifact_greatsword );
			return true;

		case k_id_cheat_create_telescope:
			artifact = get_default_artifact( k_artifact_telescope );
			return true;

		case k_id_cheat_create_shield_of_light:
			artifact = get_default_artifact( k_artifact_shield_of_light );
			return true;

		case k_id_cheat_create_leprechaun_ring:
			artifact = get_default_artifact( k_artifact_leprechauns_ring );
			return true;

		case k_id_cheat_create_poison_ring:
			artifact = get_default_artifact( k_artifact_poison_ring );
			return true;

		case k_id_cheat_create_lesser_ring_of_vulnerability:
			artifact = get_default_artifact( k_artifact_lesser_ring_of_vulnerability );
			return true;

		case  k_id_cheat_create_greater_ring_of_vulnerability:
			artifact = get_default_artifact( k_artifact_greater_ring_of_vulnerability );
			return true;

		case k_id_cheat_create_gloves:
			artifact = get_default_artifact( k_artifact_equestrians_gloves );
			return true;

		case k_id_cheat_create_binding_liquid:
			artifact = get_default_artifact( k_artifact_binding_liquid );
			return true;

		case k_id_cheat_create_cloud_of_despair:
			artifact = get_default_artifact( k_artifact_cloud_of_despair );
			return true;

		case k_id_cheat_create_holy_water:
			artifact = get_default_artifact( k_artifact_holy_water );
			return true;

		case k_id_cheat_create_demon_fire:
			artifact = get_default_artifact( k_artifact_kreegan_fire );
			return true;

		case k_id_cheat_create_cold_potion:
			artifact = get_default_artifact( k_artifact_potion_of_cold );
			return true;

		case k_id_cheat_create_endurance_potion:
			artifact = get_default_artifact( k_artifact_potion_of_endurance );
			return true;

		case k_id_cheat_create_fire_resistance:
			artifact = get_default_artifact( k_artifact_potion_of_fire_resistance );
			return true;

		case k_id_cheat_create_healing_potion:
			artifact = get_default_artifact( k_artifact_potion_of_healing );
			return true;

		case k_id_cheat_create_health_potion:
			artifact = get_default_artifact( k_artifact_potion_of_health );
			return true;

		case k_id_cheat_create_luck_potion:
			artifact = get_default_artifact( k_artifact_potion_of_luck );
			return true;

		case k_id_cheat_create_mana_potion:
			artifact = get_default_artifact( k_artifact_potion_of_mana );
			return true;

		case k_id_cheat_create_mirth_potion:
			artifact = get_default_artifact( k_artifact_potion_of_mirth );
			return true;

		case k_id_cheat_create_precognition:
			artifact = get_default_artifact( k_artifact_potion_of_immortality );
			return true;

		case k_id_cheat_create_quickness_potion:
			artifact = get_default_artifact( k_artifact_potion_of_quickness );
			return true;

		case k_id_cheat_create_restoration:
			artifact = get_default_artifact( k_artifact_potion_of_restoration );
			return true;

		case k_id_cheat_create_smoke:
			artifact = get_default_artifact( k_artifact_vial_of_blinding_smoke );
			return true;

		case k_id_cheat_create_strength_potion:
			artifact = get_default_artifact( k_artifact_potion_of_strength );
			return true;

		case k_id_cheat_create_acid:
			artifact = get_default_artifact( k_artifact_vial_of_acid );
			return true;

		case k_id_cheat_create_choking_gas:
			artifact = get_default_artifact( k_artifact_vial_of_choking_gas );
			return true;

		case k_id_cheat_create_poison_potion:
			artifact = get_default_artifact( k_artifact_vial_of_poison );
			return true;

		case k_id_cheat_create_dagger_of_despair:
			artifact = get_default_artifact( k_artifact_tynans_dagger_of_despair );
			return true;

		case k_id_cheat_create_sword_of_the_gods:
			artifact = get_default_artifact( k_artifact_sword_of_the_gods );
			return true;
	}

	return false;
}

// ----------------------------------------------------
// ----------------------------------------------------
// frame window for adventure map
// handle a menu click
// ----------------------------------------------------
bool t_adventure_frame::menu_click( int id )
{
	if (!is_visible())
		return false;

	if ( m_adventure_map_window->get_object_mover() != 0 )
		return false;

	switch (id)
	{
		case k_id_file_new_scenario:
			new_scenario();
			return true;

		case k_id_file_save_game:
			save_game();
			return true;

		case k_id_file_load_game:
			load_game();
			return true;

		case k_id_file_exit:
			quit();
			return true;

		case k_id_cheat_unlimited_move:
			
			if (m_selected_army != 0)
				unlimited_move();
			return true;

		case k_id_cheat_increase_level:
			if (m_selected_army != 0)
				free_experience();
			return true;

		case k_id_cheat_gain_skill:
			if (m_selected_army != 0)
				cheat_learn_skill();
			return true;

		case k_id_cheat_learn_spells:
			learn_spells_cheat();
			return true;
			
		case k_id_cheat_materials:
			m_adventure_map->add_free_materials();
			update_funds();
			return true;
			
		case k_id_cheat_suspend_animation:
			set_show_adventure_animations( false );
			m_adventure_map_window->enable_animation( false );
			return true;
			
		case k_id_cheat_resume_animation:
			set_show_adventure_animations( true );
			m_adventure_map_window->enable_animation( true );
			return true;
			
		case k_id_cheat_toggle_auto_play:
			set_enable_auto_play( !get_enable_auto_play() );
			toggle_players_as_ai( get_enable_auto_play() );
				
			if (get_enable_auto_play())
				m_adventure_map->stop_event_record();
			else
				m_adventure_map->start_event_record();

			if( get_enable_auto_play() )
				end_turn_click( 0 );
		
			return true;
			
		case k_id_cheat_toggle_shroud_fow:
			set_enable_shroud( !get_enable_shroud() );
			if ( m_adventure_map )
			{
				if ( get_enable_shroud() )
				{
					set_team_view();
				} else {
					set_team_view( -1 );
				}
				reset_pathfinder();
			}
			return true;

		case k_id_cheat_win_map:
		case k_id_cheat_lose_map:
			{
				t_window_ptr this_ptr = this;
				game_over(
					id == k_id_cheat_win_map ? k_game_over_result_win : k_game_over_result_lose,
					m_adventure_map->get_player().get_team() );
			}
			return true;

		case k_id_cheat_maximum_luck:
			{
				// FIXME: implement me!
			}
			return true;

		case k_id_cheat_maximum_morale:
			{
				// FIXME: implement me!
			}
			return true;

		case k_id_cheat_reveal_puzzle:
			{
				// FIXME: implement me!
			}
			return true;

		case k_id_cheat_dump_entire_map_image:
			dump_entire_map_image( *m_adventure_map, m_adventure_map_window->get_view_level() );
			return true;

		case k_id_verify_strings:
			verify_external_strings();
			return true;

		default:
		{
			t_artifact artifact;

			if (m_selected_army != 0 && create_artifact_cheat( id, artifact ))
			{
				m_selected_army->get_creatures().add( artifact );
				return true;
			}
			if (m_selected_army != 0
				&& create_creature_cheat( id, m_selected_army->get_creatures()))
			{
				update();
				return true;
			}
			break;
		}
	}
	return t_window::menu_click( id );
}

// ----------------------------------------------------
// frame window for adventure map
// get the adventure map
// ----------------------------------------------------
t_adventure_map_window* t_adventure_frame::get_map_window() const
{
	return m_adventure_map_window;
}

// ----------------------------------------------------
// frame window for adventure map
// switch to/from army mode
// ----------------------------------------------------
void t_adventure_frame::set_army_mode( bool army_mode )
{
	t_window_list::iterator window;

	m_in_army_mode = army_mode;

	if (army_mode)
	{
		m_town_list->select_town( NULL );
		if (m_army_display != 0)
		{
			if (m_selected_army == 0)
				m_army_display->set_army( 0 );
			else
			{
				m_army_display->set_army( &m_selected_army->get_creatures() );
				m_creature_detail.set_boat( m_selected_army->is_boat() );
				m_adventure_map->display_selection( m_selected_army );
			}
		}
	}
	else
	{
		m_army_list->select_army( NULL );
		if (m_army_display != 0)
		{
			if (m_selected_town == 0)
				m_army_display->set_army( 0 );
			else
			{
				m_army_display->set_army( &m_selected_town->get_garrison() );
				m_creature_detail.set_boat( false );
			}
		}
		m_adventure_map->clear_selection();
	}
}		


// ----------------------------------------------------
// frame window for adventure map
// check if we're in the edge of the window
// ----------------------------------------------------
int const k_scroll_area_width = 20;

t_direction t_adventure_frame::get_scroll_direction( t_screen_point const& point,
													 int& distance ) const
{
	int vertical_distance;

	distance = point.x;
	if (distance <= k_scroll_area_width)
	{
		if (point.y <= k_scroll_area_width)
		{
			if (distance > point.y)
				distance = point.y;
			return k_direction_northwest;
		}
		vertical_distance = get_client_rect().bottom - point.y;
		if (distance > vertical_distance)
			distance = vertical_distance;
		if (vertical_distance <= k_scroll_area_width)
			return k_direction_southwest;
		return k_direction_west;
	}
	distance = get_client_rect().right - point.x;
	if (distance <= k_scroll_area_width)
	{
		if (point.y <= k_scroll_area_width)
		{
			if (point.y < distance)
				distance = point.y;
			return k_direction_northeast;
		}
		vertical_distance = get_client_rect().bottom - point.y;
		if (distance > vertical_distance)
			distance = vertical_distance;
		if (vertical_distance <= k_scroll_area_width)
			return k_direction_southeast;
		return k_direction_east;
	}
	distance = point.y;
	if (distance <= k_scroll_area_width)
		return k_direction_north;
	distance = get_client_rect().bottom - point.y;
	if (distance <= k_scroll_area_width)
		return k_direction_south;
	return k_direction_count;
}

// ----------------------------------------------------
// frame window for adventure map
// check if we're in the edge of the window
// ----------------------------------------------------
void t_adventure_frame::mouse_move( t_mouse_event const& event )
{
	if (m_scrolling || !m_allow_scrolling)
		return;

	// check event message against current mouse position.
	if ( get_mouse_position( this ) != event.client_point )
		return;

//	int distance;
	if ( ( m_mouse_direction = get_scroll_direction( event.client_point, m_distance ) ) == k_direction_count)
		return;

	m_scrolling = true;
	if (!is_active())
		resume_idle_processing();
	on_idle();
}

// ----------------------------------------------------
// clean up before the frame closes
// ----------------------------------------------------
void t_adventure_frame::on_close()
{

}

// ----------------------------------------------------
// frame window for adventure map
// check scrolling
// ----------------------------------------------------
void t_adventure_frame::on_idle()
{
	if (!m_scrolling || !m_allow_scrolling)
	{
		suspend_idle_processing();
		set_cursor( m_normal_cursor );
		return;
	}

	int            distance = m_distance;
	t_direction    direction = k_direction_count;

	if( m_scrolling )
	{
		t_screen_point point = get_mouse_position( this );
		direction = get_scroll_direction( point, distance );
		if ( !is_point_in_rect( point, get_client_rect() ) 
			|| direction == k_direction_count)
		{
			m_scrolling = false;
			set_cursor( m_normal_cursor );
			suspend_idle_processing();
			return;
		}
	}

	if( direction != k_direction_count )
	{
		int scroll_distance = m_scroll_distance;

		m_scroll_cursor.set_frame( get_direction_name( direction ));
		set_cursor( m_scroll_cursor.cursor );
		// direction offsets are in map coordinates, so rotate 45' to get screen directions.
		direction = clockwise( direction );

		t_map_point_2d offset = get_direction_offset( direction );
		t_screen_point screen_offset;
		t_screen_point view_point = m_adventure_map_window->get_view_pos();

		if (distance < k_scroll_area_width / 4)
			scroll_distance <<= 2;
		screen_offset.x = offset.column * scroll_distance;
		screen_offset.y = offset.row * scroll_distance;
		m_adventure_map_window->move_view( view_point + screen_offset );
	}
}

// ----------------------------------------------------
// frame window for adventure map
// select first town or army
// ----------------------------------------------------
void t_adventure_frame::select_first_item()
{
	t_player& player = m_adventure_map->get_player();

	if (player.get_armies()->size() > 0)
	{
		select_army( player.get_armies()->front() );
	} 
	else if (player.get_towns()->size() > 0)
	{
		select_town( player.get_towns()->front() );
	}
	else
	{
		select_army( NULL );
		select_town( NULL );
	}
}

// Reset timer to current time.
void t_adventure_frame::reset_turn_time()
{
    m_turn_time = get_time();
    m_turn_time_elapsed = 0;
}

// Pause turn timer.
void t_adventure_frame::pause_turn_time()
{
    m_turn_time_elapsed = (get_time() - m_turn_time);
}

void t_adventure_frame::unpause_turn_time()
{
    m_turn_time = (get_time() - m_turn_time_elapsed);
    m_turn_time_elapsed = 0;
}

static t_external_string const k_text_kingdom_trade_title( "title.kingdom_trade" );
static t_external_string const k_text_kingdom_trade_intro( "description.kingdom_trade" );
static t_external_string const k_text_kingdom_trade_no_allies( "kingdom_trade_no_allies.misc" );

void t_adventure_frame::kingdom_trade()
{
	bool have_ally = false;

	// Check the player list to see if we have any allies to trade with
	for (int i=0; i<m_adventure_map->get_player_count(); i++)
    {
		t_player * player_ptr = m_adventure_map->get_players()[i].get();

		// If we have at least one potential trading partner, run the dialog
		if( is_ally( &m_adventure_map->get_player(), player_ptr ) )
		{
			have_ally = true;
			break;
		}
	}
	
	// If we have an ally, display the UI, else decline
	if (have_ally)
	{
		t_counted_ptr<t_dialog_kingdom_trade> kingdom_trade_dialog = new t_dialog_kingdom_trade( this );
		kingdom_trade_dialog->init_dialog( this, this, k_text_kingdom_trade_title, k_text_kingdom_trade_intro );
		kingdom_trade_dialog->run_modal();
	}
	else
	{
		ok_dialog( k_text_kingdom_trade_no_allies, true );
	}
}

static t_external_string const k_text_marketplace_title( "market_place.misc" );
static t_external_string const k_text_marketplace_intro( "market_place_intro.misc" );

// Always 1:k_marketplace_ratio_efficiency
static int const k_marketplace_ratio_efficiency = 3;

void t_adventure_frame::marketplace()
{
	if ( m_adventure_map_window->get_object_mover() != 0 )
		return;

	t_counted_ptr<t_dialog_marketplace> marketplace_dialog = new t_dialog_marketplace( this );

	marketplace_dialog->init_dialog( this, this, k_text_marketplace_title, k_text_marketplace_intro,
                    k_marketplace_ratio_efficiency );
	marketplace_dialog->run_modal();
	update_funds();
}

void t_adventure_frame::scenario_info()
{
	t_counted_ptr<t_scenario_info_window> scenario_window = new t_scenario_info_window ( this, m_adventure_map );

	scenario_window->run_modal();
}

void t_adventure_frame::kingdom_overview_click( t_button* )
{
	kingdom_overview();
}

void t_adventure_frame::kingdom_overview()
{
	t_counted_ptr<t_kingdom_overview_window> overview_window = new t_kingdom_overview_window( this, this, &m_adventure_map->get_player() );

	overview_window->run_modal();
}

void t_adventure_frame::thieves_guild()
{
	t_counted_ptr<t_thieves_guild_window> thieves_guild = new t_thieves_guild_window( this, *m_adventure_map );

	thieves_guild->run_modal();
}

void t_adventure_frame::quest_log_click( t_button* )
{
    quest_log_window();
}

void t_adventure_frame::quest_log_window()
{
	t_counted_ptr<t_quest_log_window> quest_log_window = new t_quest_log_window( this, this );
	quest_log_window->run_modal();
}

void t_adventure_frame::puzzle_window_click( t_button* )
{
    puzzle_window();
}

static t_external_string const k_text_no_obelisks_visited( "no_obelisks_visited.dialog" );
void t_adventure_frame::puzzle_window()
{
    t_obelisk_color color;
    bool    any_obelisks_visited = false;
    t_player * player_ptr = &m_adventure_map->get_player();

    for (color = k_obelisk_gold; color < k_obelisk_color_count; enum_incr( color ))
    {
        // Any obelisks of this color on map?
        if ( m_adventure_map->get_required_obelisks( color ) > 0 )
        {
            if (player_ptr->get_obelisk_count( color ) > 0)
                any_obelisks_visited = true;
        }
    }
    if (any_obelisks_visited == false)
    {
		ok_dialog( k_text_no_obelisks_visited );
        return;
    }

	t_counted_ptr<t_puzzle_window> puzzle_window = new t_puzzle_window( this, this, &m_adventure_map->get_player() );

	puzzle_window->run_modal();
}

	
// ----------------------------------------------------
// View all the caravans the player knows about
// ----------------------------------------------------
void t_adventure_frame::view_caravan()
{
	t_counted_ptr< t_dialog_caravan_view > dialog = new t_dialog_caravan_view( this, *m_adventure_map );

	if ( dialog->init_dialog( NULL ) )
		dialog->run_modal();
}

// ----------------------------------------------------
// ----------------------------------------------------
void t_adventure_frame::view_world()
{
	t_screen_point center_point =
		m_adventure_map_window->get_view_pos() + m_adventure_map_window->get_view_size() / 2;
	int view_level = m_adventure_map_window->get_view_level();
	int team_view = m_adventure_map_window->get_team_view();

	t_counted_ptr< t_view_world_dialog > dialog_ptr =
		new t_view_world_dialog( this, *m_adventure_map, center_point, view_level, team_view );
	dialog_ptr->run_modal();
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
t_mini_map_window* t_adventure_frame::get_mini_map_window()
{
	return m_mini_map;
}

//-----------------------------------------------------------------------------
// sets the view level for both the map renderer and the mini-map in lock step
//-----------------------------------------------------------------------------
void t_adventure_frame::set_view_level( int new_view_level )
{

	if(	m_adventure_map->get_num_levels() <= 1 )
	{
		if( m_underground_button )
		{
			m_underground_button->enable( false );
			m_underground_button->set_visible( true );
		}
		if( m_surface_button )
			m_surface_button->set_visible( false );
		return;
	}
	else if (new_view_level == 1)
	{
		if( m_surface_button )
		{
			m_surface_button->enable( true );
			m_surface_button->set_visible( true );
		}
		if( m_underground_button )
			m_underground_button->set_visible( false );
	}
	else
	{
		if( m_underground_button )
		{
			m_underground_button->enable( true );
			m_underground_button->set_visible( true );
		}
		if( m_surface_button )
			m_surface_button->set_visible( false );
	}

	get_map_window()->set_view_level( new_view_level );
	m_mini_map->set_view_level( new_view_level );
}

// -----------------------------------------------------------------------
// go through all the players and evaluate whether the game has
// been won or lost yet
// -----------------------------------------------------------------------
static t_external_string const k_player_eliminated( "eliminated.adventure_map" );
static t_external_string const k_default_name( "default_name.adventure_map" );
static t_external_string const k_red_color( "red.adventure_map" );
static t_external_string const k_green_color( "green.adventure_map" );
static t_external_string const k_blue_color( "blue.adventure_map" );
static t_external_string const k_orange_color( "orange.adventure_map" );
static t_external_string const k_purple_color( "purple.adventure_map" );
static t_external_string const k_teal_color( "teal.adventure_map" );
static t_external_string const k_gray_color( "gray.adventure_map" );
static t_external_string const k_and( "and.combat" );
static t_external_string const k_victory_initiated( "victory_initiated.adventure_map" );
static t_external_string const k_victory_terminated( "victory_terminated.adventure_map" );

void t_adventure_frame::evaluate_victory_condition()
{
	int i;
	int active_cnt = 0;
	bool any_were_eliminated = false;
	bool all_humans_are_dead = true;
	std::string elim_text;

	// Game is over, stop evaluating this!
	if ( !is_open() || m_adventure_map->is_game_over() )
		return;

	// Handle special auto-play cheat victory condition
	// This is a lot of bs for a stupid cheat! Bah!
	if( get_enable_auto_play() )
	{
		int last_ai = 0;
		int last_team = -1;
		int player_count = m_adventure_map->get_player_count();
		for (i = 0; i < player_count; i++)
		{
			t_player & player = m_adventure_map->get_player( i );
			bool is_eliminated = player.is_eliminated();

			// keep track of player counts
			if( !is_eliminated )
			{
				if (player.has_lost())
				{
					player.eliminate();
				}
				else
				{
					active_cnt++;
					last_ai = i;
					if( last_team == -1 )
						last_team = player.get_team();
					else 
					if( last_team != player.get_team() )
						return;	// teams differ, so game is not over
				}
			}
		}

		if( active_cnt == 0 ) // everyone died
		{
			// game over - you lose
			game_over( k_game_over_result_lose );
		} else
		{
			int win_team = m_adventure_map->get_player( last_ai ).get_team();
			// game over - you win
			game_over( k_game_over_result_win, win_team );
		}

		return;
	}

	// Display a dialog for each newly eliminated player
	// if there are any
	int player_count = m_adventure_map->get_player_count();
	int elim_cnt = 0;
	for (i = 0; i < player_count; i++)
	{
		t_player & player = m_adventure_map->get_player( i );

		bool is_eliminated = player.is_eliminated() || player.has_lost();

		// keep track of player counts
		if( !is_eliminated )
		{
			active_cnt++;
			
			if (!player.is_computer())
				all_humans_are_dead = false;
		} 

		if( is_eliminated && !player.is_eliminated() )
		{
			player.eliminate();

			std::string text = k_player_eliminated;
			std::string name = k_default_name;	// NOTE: this is a variable so it could be replaced with a name
			std::string color;

			switch( player.get_color() )
			{
				case k_player_red:
					color = k_red_color;
					break;
				case k_player_green:
					color = k_green_color;
					break;
				case k_player_blue:
					color = k_blue_color;
					break;
				case k_player_orange:
					color = k_orange_color;
					break;
				case k_player_purple:
					color = k_purple_color;
					break;
				case k_player_teal:
					color = k_teal_color;
					break;
				case k_player_gray:
					color = k_gray_color;
					break;
			}

		    text = replace_keywords( text, "%name", name, "%color", color );
			if( elim_cnt++ > 0 )
			{
				elim_text += k_and;
				elim_text += '\n';
			}
			elim_text += text;
			any_were_eliminated = true;
		}
	}

	// if any players were eliminated, show it
	if( any_were_eliminated && !get_enable_auto_play() )
	{
		t_counted_ptr<t_basic_dialog> eliminated_dialog_ptr;

		eliminated_dialog_ptr = new t_basic_dialog;
		eliminated_dialog_ptr->set_text( elim_text ); 

		eliminated_dialog_ptr->add_ok_button();
		eliminated_dialog_ptr->open();
		eliminated_dialog_ptr->run_modal();
	}

	// If all human players have been eliminated, lose the game
	if( all_humans_are_dead )
	{
		game_over( k_game_over_result_lose );
	} 
	else
	{
		if (!m_adventure_map->get_standard_victory_condition())
			return;

		if( !m_adventure_map->get_current_player().is_computer() )
		{
			if ( active_cnt == 1)
			{
				game_over( k_game_over_result_win, m_adventure_map->get_current_player().get_team() );
				return;
			}

			int which_team = m_adventure_map->which_team_owns_all_towns();
			if ( which_team != -1 ) 
			{
				if (m_adventure_map->get_winning_team() == -1)
				{
					ok_dialog( k_victory_initiated );
					m_adventure_map->set_winning_team( which_team );
				}
			} 
			else
			{
				if ( m_adventure_map->get_winning_team() != -1 )
				{
					ok_dialog( k_victory_terminated );
					m_adventure_map->set_winning_team(-1);
				}
			}
		} 
		else 
		{
			if ( m_adventure_map->get_winning_team() != -1 ) 
			{
				int which_team = m_adventure_map->which_team_owns_all_towns();
				if (which_team == -1)
				{
					if (m_adventure_map->get_player().get_team() == m_adventure_map->get_winning_team())
						ok_dialog( k_victory_terminated );
					m_adventure_map->set_winning_team( -1 );
				}
			}
		}
	}
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
void t_adventure_frame::do_end_game_dialogs()
{
	// We only both with scoring or campaign advance if we won the scenario
	if( m_game_result == k_game_over_result_win )
	{
		if( !m_adventure_map->is_multi_scenario() )
		{
			// Just present the scenario score and we're done
			t_counted_ptr<t_score_dialog> score_dialog;
			score_dialog = new t_score_dialog( t_window::get_main_window(), *m_adventure_map, m_winner_team );
			score_dialog->run_modal();
		}
		else
		{
			// Score the map
			t_final_scores score_data;
			calculate_scores( *m_adventure_map, m_winner_team, score_data );

			// Store this maps final score
			m_adventure_map->store_map_score( score_data.final_score, score_data.days );

			// Save the parent before the close so they can be given to the new frame			
			t_window * parent_ptr = t_window::get_main_window();

			// Try to load the next map
			bool no_more_maps;
			t_adventure_map_ptr next_map_ptr = read_next_scenario( parent_ptr, *m_adventure_map, &no_more_maps );
			if ( next_map_ptr )
			{
				m_win_lose_window->close();

				// Create a new frame for the next map
				t_counted_ptr< t_adventure_frame > next_frame_ptr( new t_adventure_frame( next_map_ptr, parent_ptr ) );
				next_frame_ptr->start_new_game( next_map_ptr );

				// We DO NOT want to go back to the main menu...
				return;
			}
			else if (no_more_maps)
			{
				// No more maps in the campaign, show the campaign score screen
				t_counted_ptr<t_dialog_campaign_score> campaign_score_dialog;
				campaign_score_dialog = new t_dialog_campaign_score( m_adventure_map, score_data.human_player->get_name(), t_window::get_main_window() );
				campaign_score_dialog->run_modal();
			}
		}
	}

	// back to the main menu
	m_win_lose_window->close();
	main_menu();
}


// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
void t_adventure_frame::play_win_lose_cinematic()
{
	// Keep a counted pointer to this to keep this from being deleted by the close
	t_window_ptr this_ptr = this;
	close();

	// create the cinematic window
	t_win_lose_window * win_lose_window = new t_win_lose_window( t_window::get_main_window(),
		bound_handler( *this, &t_adventure_frame::do_end_game_dialogs ) );

	m_win_lose_window = win_lose_window;

	t_sound_cache music = get_music_playing();
	stop_music();

	// play a cinematic
	win_lose_window->run_modal(true);

	play_music( music );
}

// -----------------------------------------------------------------------
// handle game over conditions
// -----------------------------------------------------------------------
void t_adventure_frame::game_over( t_game_over_result result, int team_num )
{
	if ( m_adventure_map->is_game_over() )
		return;

	m_game_result = result;
	m_winner_team = team_num;

	// fade out the active sounds list
	close_active_sounds();

	// set the map validity to false
	m_adventure_map->set_game_over( true );

	// Note:  this call will "close" this adventure frame window
	play_win_lose_cinematic();
}


// -----------------------------------------------------------------------
// turns auto play on/off
// -----------------------------------------------------------------------
void t_adventure_frame::toggle_players_as_ai( bool all_ai )
{
	struct t_player_info
	{
		bool			is_computer;
	};

	t_player_list const &	player_slots = get_map()->get_players();
	static t_player_info saved_players[k_player_color_count];

	if( all_ai )
	{
		for( int player_num = 0; player_num < player_slots.size(); ++player_num ) 
		{
			t_player & player = get_map()->get_player( player_num );


			saved_players[player_num].is_computer = player.is_computer();			

//			player.set_to_computer();
			player.set_to_player( true );
		}
	}
	else
	{
		for( int player_num = 0; player_num < player_slots.size(); ++player_num ) 
		{
			t_player & player = get_map()->get_player( player_num );
			t_player_info const & info = saved_players[player_num];

			player.set_to_player( info.is_computer );
		}
	}
}

// -----------------------------------------------------------------------
// sleeps/wakes the currently selected army
// -----------------------------------------------------------------------
void t_adventure_frame::sleep_selected_army( bool is_asleep )
{
	t_army * selected_army = get_selected_army();

	if( selected_army )
	{
		selected_army->set_sleeping( is_asleep );
		if( is_asleep )
			ok_dialog( k_text_army_sleep ); 
		else
			ok_dialog( k_text_army_wake );
	}
}

// -----------------------------------------------------------------------
// center the view on the currently selected town/creature stack
// -----------------------------------------------------------------------
void t_adventure_frame::center_view_on_selected_creature()
{
	t_creature_array * creatures = get_selected_creatures(); 

	if( creatures )
	{
		t_adventure_object * object = creatures->get_adventure_object();
		if( object )
		{
			t_adv_map_point result;
			if( object->get_trigger_cell( result ) )
				get_map_window()->center_view( result );
		}
	}
}

// -----------------------------------------------------------------------
// Hides all of the player specific info
// -----------------------------------------------------------------------
void t_adventure_frame::hide_player_info()
{
	set_team_view( k_player_gray );
	set_view_level( 0 );

	assert( m_adventure_map_window != 0 );
	m_adventure_map_window->move_view( t_screen_point( 0, 0 ) );

	m_material_display.set_visible( false );
	m_material_display_gold.set_visible( false );
	m_town_list->set_visible( false );
	m_army_list->set_visible( false );
}

// -----------------------------------------------------------------------
// Undoes effects of hide_player_info() above
// -----------------------------------------------------------------------
void t_adventure_frame::show_player_info()
{
	m_material_display.set_visible( true );
	m_material_display_gold.set_visible( true );
	m_town_list->set_visible( true );
	m_army_list->set_visible( true );
}
